/** * Gets all attribute names of an extended variable name. This is useful for tab completion. */ std::vector<std::string> lua_kernel_base::get_attribute_names(const std::string & input) { std::vector<std::string> ret; std::string base_path = input; size_t last_dot = base_path.find_last_of('.'); std::string partial_name = base_path.substr(last_dot + 1); base_path.erase(last_dot); std::string load = "return " + base_path; lua_State* L = mState; int save_stack = lua_gettop(L); int result = luaL_loadstring(L, load.c_str()); if(result != LUA_OK) { // 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. LOG_LUA << "Error when attempting tab completion:\n"; LOG_LUA << luaL_checkstring(L, -1) << '\n'; // Just return an empty list; no matches were found lua_settop(L, save_stack); return ret; } luaW_pcall(L, 0, 1); if(lua_istable(L, -1) || lua_isuserdata(L, -1)) { int top = lua_gettop(L); int obj = lua_absindex(L, -1); if(luaL_getmetafield(L, obj, "__tab_enum") == LUA_TFUNCTION) { lua_pushvalue(L, obj); lua_pushlstring(L, partial_name.c_str(), partial_name.size()); luaW_pcall(L, 2, 1); ret = lua_check<std::vector<std::string>>(L, -1); } else { lua_settop(L, top); // Metafunction not found, so use lua_next to enumerate the table for(lua_pushnil(L); lua_next(L, obj); lua_pop(L, 1)) { if(lua_isstring(L, -2)) { std::string attr = lua_tostring(L, -2); if(attr.empty()) { continue; } if(!isalpha(attr[0]) && attr[0] != '_') { continue; } if(std::any_of(attr.begin(), attr.end(), [](char c){ return !isalpha(c) && !isdigit(c) && c != '_'; })) { continue; } if(attr.substr(0, partial_name.size()) == partial_name) { ret.push_back(base_path + "." + attr); } } } } } lua_settop(L, save_stack); return ret; }
lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engine_lua *engine) { int res_ai = luaL_loadstring(L, code);//stack size is now 1 [ -1: ai_context] if (res_ai) { char const *m = lua_tostring(L, -1); ERR_LUA << "error while initializing ai: " <<m << '\n'; lua_pop(L, 2);//return with stack size 0 [] return NULL; } //push data table here generate_and_push_ai_table(L, engine); //compile the ai as a closure if (!luaW_pcall(L, 1, 1, true)) { return NULL;//return with stack size 0 [] } // Retrieve the ai elements table from the registry. lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey))); lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f] // Push the function in the table so that it is not collected. size_t length_ai = lua_rawlen(L, -1);//length of ais_table lua_pushvalue(L, -2); //stack size is now 3: [-1: ai_context -2: ais_table -3: ai_context] lua_rawseti(L, -2, length_ai + 1);// ais_table[length+1]=ai_context. stack size is now 2 [-1: ais_table -2: ai_context] lua_pop(L, 2); return new lua_ai_context(L, length_ai + 1, engine->get_readonly_context().get_side()); }
void lua_ai_action_handler::handle(config &cfg, bool configOut, lua_object_ptr l_obj) { int initial_top = lua_gettop(L);//get the old stack size // Load the user function from the registry. lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey)));//stack size is now 1 [-1: ais_table key] lua_rawget(L, LUA_REGISTRYINDEX);//stack size is still 1 [-1: ais_table] lua_rawgeti(L, -1, num_);//stack size is 2 [-1: ai_action -2: ais_table] lua_remove(L, -2);//stack size is 1 [-1: ai_action] //load the lua ai context as a parameter context_.load();//stack size is 2 [-1: ai_context -2: ai_action] if (!configOut) { luaW_pushconfig(L, cfg); luaW_pcall(L, 2, 0, true); } else if (luaW_pcall(L, 1, 5, true)) // @note for Crab: how much nrets should we actually have here { // there were 2 initially, but aspects like recruitment pattern l_obj->store(L, initial_top + 1); // return a lot of results } lua_settop(L, initial_top);//empty stack }
lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engine_lua *engine) { int res_ai = luaL_loadstring(L, code);//stack size is now 1 [ -1: ai_context] if (res_ai) { char const *m = lua_tostring(L, -1); ERR_LUA << "error while initializing ai: " <<m << '\n'; lua_pop(L, 2);//return with stack size 0 [] return NULL; } //push data table here lua_newtable(L);// stack size is 2 [ -1: new table, -2: ai as string ] lua_pushinteger(L, engine->get_readonly_context().get_side()); lua_setfield(L, -2, "side");//stack size is 2 [- 1: new table; -2 ai as string] static luaL_Reg const callbacks[] = { { "attack", &cfun_ai_execute_attack }, // Move maps { "get_new_dst_src", &cfun_ai_get_dstsrc }, { "get_new_src_dst", &cfun_ai_get_srcdst }, { "get_new_enemy_dst_src", &cfun_ai_get_enemy_dstsrc }, { "get_new_enemy_src_dst", &cfun_ai_get_enemy_srcdst }, { "recalculate_move_maps", &cfun_ai_recalculate_move_maps }, { "recalculate_enemy_move_maps",&cfun_ai_recalculate_move_maps_enemy }, // End of move maps // Goals and targets { "get_targets", &cfun_ai_get_targets }, // End of G & T // Aspects { "get_aggression", &cfun_ai_get_aggression }, { "get_avoid", &cfun_ai_get_avoid }, { "get_attack_depth", &cfun_ai_get_attack_depth }, { "get_attacks", &cfun_ai_get_attacks }, { "get_caution", &cfun_ai_get_caution }, { "get_grouping", &cfun_ai_get_grouping }, { "get_leader_aggression", &cfun_ai_get_leader_aggression }, { "get_leader_goal", &cfun_ai_get_leader_goal }, { "get_leader_ignores_keep", &cfun_ai_get_leader_ignores_keep}, { "get_leader_value", &cfun_ai_get_leader_value }, { "get_number_of_possible_recruits_to_force_recruit", &cfun_ai_get_number_of_possible_recruits_to_force_recruit}, { "get_passive_leader", &cfun_ai_get_passive_leader }, { "get_passive_leader_shares_keep", &cfun_ai_get_passive_leader_shares_keep}, { "get_recruitment_ignore_bad_combat", &cfun_ai_get_recruitment_ignore_bad_combat}, { "get_recruitment_ignore_bad_movement", &cfun_ai_get_recruitment_ignore_bad_movement}, { "get_recruitment_pattern", &cfun_ai_get_recruitment_pattern }, { "get_scout_village_targeting", &cfun_ai_get_scout_village_targeting }, { "get_simple_targeting", &cfun_ai_get_simple_targeting }, { "get_support_villages", &cfun_ai_get_support_villages }, { "get_village_value", &cfun_ai_get_village_value }, { "get_villages_per_scout", &cfun_ai_get_villages_per_scout }, // End of aspects // Validation/cache functions { "is_dst_src_valid", &cfun_ai_is_dst_src_valid }, { "is_enemy_dst_src_valid", &cfun_ai_is_dst_src_enemy_valid }, { "is_src_dst_valid", &cfun_ai_is_src_dst_valid }, { "is_enemy_src_dst_valid", &cfun_ai_is_src_dst_enemy_valid }, // End of validation functions { "move", &cfun_ai_execute_move_partial }, { "move_full", &cfun_ai_execute_move_full }, { "recall", &cfun_ai_execute_recall }, { "recruit", &cfun_ai_execute_recruit }, { "stopunit_all", &cfun_ai_execute_stopunit_all }, { "stopunit_attacks", &cfun_ai_execute_stopunit_attacks }, { "stopunit_moves", &cfun_ai_execute_stopunit_moves }, { "suitable_keep", &cfun_ai_get_suitable_keep }, { "check_recall", &cfun_ai_check_recall }, { "check_move", &cfun_ai_check_move }, { "check_stopunit", &cfun_ai_check_stopunit }, { "check_attack", &cfun_ai_check_attack }, { "check_recruit", &cfun_ai_check_recruit }, //{ "",}, //{ "",}, { NULL, NULL } }; for (const luaL_Reg *p = callbacks; p->name; ++p) { lua_pushlightuserdata(L, engine); lua_pushcclosure(L, p->func, 1); lua_setfield(L, -2, p->name); } //compile the ai as a closure if (!luaW_pcall(L, 1, 1, true)) { return NULL;//return with stack size 0 [] } // Retrieve the ai elements table from the registry. lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey))); lua_rawget(L, LUA_REGISTRYINDEX); //stack size is now 2 [-1: ais_table -2: f] // Push the function in the table so that it is not collected. size_t length_ai = lua_rawlen(L, -1);//length of ais_table lua_pushvalue(L, -2); //stack size is now 3: [-1: ai_context -2: ais_table -3: ai_context] lua_rawseti(L, -2, length_ai + 1);// ais_table[length+1]=ai_context. stack size is now 2 [-1: ais_table -2: ai_context] lua_pop(L, 2); return new lua_ai_context(L, length_ai + 1, engine->get_readonly_context().get_side()); }