26 #include "formula/callable_objects.hpp" 30 #include <boost/dynamic_bitset.hpp> 31 #include <boost/range/iterator_range.hpp> 32 #include <unordered_map> 37 #define LOG_LMG LOG_STREAM(info, log_scripting_lua_mapgen) 38 #define ERR_LMG LOG_STREAM(err, log_scripting_lua_mapgen) 50 using knows_sets_t = std::map<std::string, std::set<map_location>>;
57 #define LOG_MATCHES(NAME) \ 58 LOG_LMG << #NAME << ":matches(" << l << ") line:" << __LINE__ << "\n"; 61 template<
typename T,
typename... Args>
64 return std::unique_ptr<T>(
new T(std::forward<Args>(args)...));
70 bool iswhitespace(
char c)
72 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
80 while(!s.
empty() && iswhitespace(s.
back())) {
93 int partend = s.
find(sep);
94 if(partend ==
int(string_view::npos)) {
110 int res = strtol(&s[0], end, 10);
114 std::pair<int, int> parse_single_range(
string_view s)
116 int dash_pos = s.
find(
'-');
117 if(dash_pos ==
int(string_view::npos)) {
124 return {atoi(first), atoi(second)};
133 auto pair = parse_single_range(part);
134 int m = std::max(pair.first, pair.second);
135 if(m >=
int(res.size())) {
137 for(
int i = pair.first;
i <= pair.second; ++
i) {
151 bool last_was_n =
false;
152 while(!str.
empty()) {
153 switch(str.
front()) {
180 odd.emplace_back(se, s + se/2);
181 even.emplace_back(se, s + se/2);
184 odd.emplace_back(se, s + (se - 1)/2);
185 even.emplace_back(se, s + (se + 1)/2);
193 parse_rel(part, even, odd);
208 LOG_LMG <<
"push_locationset\n";
227 std::set<map_location> res;
230 for(
size_t i = 0;
i != len; ++
i) {
258 LOG_LMG <<
"creating con filter\n";
260 for(
size_t i = 1;
i != len; ++
i) {
262 list_.emplace_back(build_filter(L, res_index, ks));
266 std::vector<std::unique_ptr<filter_impl>> list_;
269 class and_filter :
public con_filter
273 : con_filter(L, res_index, ks)
275 LOG_LMG <<
"created and filter\n";
281 for(
const auto& pfilter : list_) {
282 if(!pfilter->matches(m, l)) {
290 class or_filter :
public con_filter
294 : con_filter(L, res_index, ks)
296 LOG_LMG <<
"created or filter\n";
302 for(
const auto& pfilter : list_) {
303 if(pfilter->matches(m, l)) {
311 class nand_filter :
public con_filter
315 : con_filter(L, res_index, ks)
317 LOG_LMG <<
"created nand filter\n";
323 for(
const auto& pfilter : list_) {
324 if(!pfilter->matches(m, l)) {
332 class nor_filter :
public con_filter
336 : con_filter(L, res_index, ks)
338 LOG_LMG <<
"created nor filter\n";
344 for(
const auto& pfilter : list_) {
345 if(pfilter->matches(m, l)) {
360 LOG_LMG <<
"creating cached filter\n";
362 filter_ = build_filter(L, res_index, ks);
372 if(
int(cache_.size()) != cache_size) {
375 if(cache_[loc_index]) {
376 return cache_[loc_index + 1];
379 bool res = filter_->matches(m, l);
380 cache_[loc_index] =
true;
381 cache_[loc_index + 1] = res;
386 std::unique_ptr<filter_impl> filter_;
396 LOG_LMG <<
"creating x filter\n";
404 return l.
x >= 0 && l.
x < int(filter_.size()) && filter_[l.
x];
415 LOG_LMG <<
"creating y filter\n";
424 return l.
y >= 0 && l.
y < int(filter_.size()) && filter_[l.
y];
435 LOG_LMG <<
"creating onborder filter\n";
451 LOG_LMG <<
"creating terrain filter\n";
468 static const offset_list_t even_offsets_default = {{1 , 0}, {1 , 1}, {0 , 1}, {-1 , 1}, {-1 , 0}, {0, -1}};
469 static const offset_list_t odd_offsets_default = {{1 , -1}, {1 , 0}, {0 , 1}, {-1 , 0}, {-1 , -1}, {0, -1}};
477 LOG_LMG <<
"creating adjacent filter\n";
479 parse_rel_sequence(
luaW_tostring(L, -1), even_offsets_, odd_offsets_);
483 even_offsets_ = even_offsets_default;
484 odd_offsets_ = odd_offsets_default;
491 filter_ = build_filter(L, res_index, ks);
501 for(
const auto& offset : offsets) {
503 if(m.
on_map(ad) && filter_->matches(m, ad)) {
504 if(accepted_counts_.size() == 0) {
510 return int(accepted_counts_.size()) > count && accepted_counts_[count];
515 std::unique_ptr<filter_impl> filter_;
524 LOG_LMG <<
"creating findin filter\n";
530 auto insert_res = ks.insert(knows_sets_t::value_type{id, {}});
531 if(insert_res.second && res_index > 0) {
538 set_ = &insert_res.first->second;
544 return set_->find(l) != set_->end();
560 LOG_LMG <<
"creating radius filter\n";
562 filter_radius_ = build_filter(L, res_index, ks);
569 filter_ = build_filter(L, res_index, ks);
576 std::set<map_location> result;
583 return !filter_radius_ || filter_radius_->matches(m, l);
588 if(!filter_ || filter_->matches(m, lr)) {
596 std::unique_ptr<filter_impl> filter_radius_;
597 std::unique_ptr<filter_impl> filter_;
606 LOG_LMG <<
"creating formula filter\n";
612 formula_ = utils::make_unique<wfl::formula>(code);
623 return (formula_.get() !=
nullptr) && formula_->evaluate(callable).as_bool();
629 std::unique_ptr<wfl::formula> formula_;
633 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 };
636 static const std::unordered_map<std::string, filter_keys> keys {
639 {
"not_all", F_NAND },
643 {
"find_in", F_FIND_IN },
644 {
"adjacent", F_ADJACENT },
645 {
"terrain", F_TERRAIN },
646 {
"cached", F_CACHED },
647 {
"formula", F_FORMULA },
648 {
"radius", F_RADUIS }
653 LOG_LMG <<
"buildfilter: start\n";
659 LOG_LMG <<
"buildfilter: got: " << s <<
"\n";
660 auto it = keys.find(s);
661 if(it == keys.end()) {
665 auto key = it->second;
670 return utils::make_unique<and_filter>(L, res_index, ks);
672 return utils::make_unique<or_filter>(L, res_index, ks);
674 return utils::make_unique<nand_filter>(L, res_index, ks);
676 return utils::make_unique<nor_filter>(L, res_index, ks);
678 return utils::make_unique<x_filter>(L, res_index, ks);
680 return utils::make_unique<y_filter>(L, res_index, ks);
682 return utils::make_unique<findin_filter>(L, res_index, ks);
684 return utils::make_unique<adjacent_filter>(L, res_index, ks);
686 return utils::make_unique<terrain_filter>(L, res_index, ks);
688 return utils::make_unique<radius_filter>(L, res_index, ks);
690 return utils::make_unique<cached_filter>(L, res_index, ks);
692 return utils::make_unique<formula_filter>(L, res_index, ks);
694 throw "invalid filter key enum";
704 filter::filter(
lua_State* L,
int data_index,
int res_index)
706 LOG_LMG <<
"creating filter object\n";
708 impl_ = build_filter(L, res_index, known_sets_);
710 LOG_LMG <<
"finished creating filter object\n";
716 return impl_->matches(m, l);
729 LOG_LMG <<
"map:get_locations vaidargs\n";
731 LOG_LMG <<
"map:get_locations some locations\n";
733 LOG_LMG <<
"map:get_locations #args = " << s.size() <<
"\n";
741 LOG_LMG <<
"map:get_locations all locations\n";
748 LOG_LMG <<
"map:get_locations #res = " << res.size() <<
"\n";
750 LOG_LMG <<
"map:get_locations end\n";
757 LOG_LMG <<
"map:get_locations\n";
811 throw "luaW_type_error didn't throw";
819 template<
typename... T>
822 LOG_LMG <<
"luaW_push_mgfilter\n";
875 std::string err_msg =
"unknown modifiable property of map: ";
904 std::ostringstream cmd_out;
906 cmd_out <<
"Adding terrainmamap metatable...\n";
921 return cmd_out.str();
bool luaW_tableget(lua_State *L, int index, const char *key)
BOOST_CXX14_CONSTEXPR void remove_suffix(size_type n)
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)
BOOST_CXX14_CONSTEXPR size_type find(basic_string_view s, size_type pos=0) const BOOST_NOEXCEPT
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)
BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n)
BOOST_CXX14_CONSTEXPR basic_string_view substr(size_type pos, size_type n=npos) const
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)
basic_string_view< char, std::char_traits< char > > string_view
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)
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_
BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
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).
std::unique_ptr< T > make_unique(Args &&... args)
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 const ::config * terrain
The terrain used to create the cache.
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.
BOOST_CONSTEXPR const_reference back() const
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.
BOOST_CONSTEXPR const_reference front() const
#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
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)