/** * Gets the parsed field of a vconfig object (_index metamethod). * Special fields __literal, __shallow_literal, __parsed, and * __shallow_parsed, return Lua tables. */ static int impl_vconfig_get(lua_State *L) { vconfig *v = static_cast<vconfig *>(lua_touserdata(L, 1)); if (lua_isnumber(L, 2)) { vconfig::all_children_iterator i = v->ordered_begin(); unsigned len = std::distance(i, v->ordered_end()); unsigned pos = lua_tointeger(L, 2) - 1; if (pos >= len) return 0; std::advance(i, pos); lua_createtable(L, 2, 0); lua_pushstring(L, i.get_key().c_str()); lua_rawseti(L, -2, 1); luaW_pushvconfig(L, vconfig(i.get_child())); lua_rawseti(L, -2, 2); return 1; } char const *m = luaL_checkstring(L, 2); if (strcmp(m, "__literal") == 0) { luaW_pushconfig(L, v->get_config()); return 1; } if (strcmp(m, "__parsed") == 0) { luaW_pushconfig(L, v->get_parsed_config()); return 1; } bool shallow_literal = strcmp(m, "__shallow_literal") == 0; if (shallow_literal || strcmp(m, "__shallow_parsed") == 0) { lua_newtable(L); BOOST_FOREACH(const config::attribute &a, v->get_config().attribute_range()) { if (shallow_literal) luaW_pushscalar(L, a.second); else luaW_pushscalar(L, v->expand(a.first)); lua_setfield(L, -2, a.first.c_str()); } vconfig::all_children_iterator i = v->ordered_begin(), i_end = v->ordered_end(); if (shallow_literal) { i.disable_insertion(); i_end.disable_insertion(); } for (int j = 1; i != i_end; ++i, ++j) { lua_createtable(L, 2, 0); lua_pushstring(L, i.get_key().c_str()); lua_rawseti(L, -2, 1); luaW_pushvconfig(L, i.get_child()); lua_rawseti(L, -2, 2); lua_rawseti(L, -2, j); } return 1; }
/** * Gets some data on a unit type (__index metamethod). * - Arg 1: table containing an "id" field. * - Arg 2: string containing the name of the property. * - Ret 1: something containing the attribute. */ static int impl_unit_type_get(lua_State *L) { char const *m = luaL_checkstring(L, 2); lua_pushstring(L, "id"); lua_rawget(L, 1); const unit_type *utp = unit_types.find(lua_tostring(L, -1)); if (!utp) return luaL_argerror(L, 1, "unknown unit type"); unit_type const &ut = *utp; // Find the corresponding attribute. return_tstring_attrib("name", ut.type_name()); return_int_attrib("max_hitpoints", ut.hitpoints()); return_int_attrib("max_moves", ut.movement()); return_int_attrib("max_experience", ut.experience_needed()); return_int_attrib("cost", ut.cost()); return_int_attrib("level", ut.level()); return_int_attrib("recall_cost", ut.recall_cost()); return_cfgref_attrib("__cfg", ut.get_cfg()); if (strcmp(m, "traits") == 0) { lua_newtable(L); BOOST_FOREACH(const config& trait, ut.possible_traits()) { const std::string& id = trait["id"]; lua_pushlstring(L, id.c_str(), id.length()); luaW_pushconfig(L, trait); lua_rawset(L, -3); } return 1; }
void lua_kernel_base::run_lua_tag(const config& cfg) { int nArgs = 0; if (const config& args = cfg.child("args")) { luaW_pushconfig(this->mState, args); ++nArgs; } this->run(cfg["code"].str().c_str(), cfg["name"].str(), nArgs); }
static int impl_context_accessor(lua_State * L, std::shared_ptr<lua_context_backend> backend, plugins_context::accessor_function func) { if (!backend->valid) { luaL_error(L , "Error, you tried to use an invalid context object in a lua thread"); } if(lua_gettop(L)) { config temp; if(!luaW_toconfig(L, 1, temp)) { luaL_argerror(L, 1, "Error, tried to parse a config but some fields were invalid"); } luaW_pushconfig(L, func(temp)); return 1; } else { luaW_pushconfig(L, func(config())); return 1; } }
/** * Returns a clone (deep copy) of the passed config, which can be either a normal config or a vconfig * If it is a vconfig, the underlying config is also cloned. * - Arg 1: a config * - Ret: the cloned config */ static int intf_clone_wml(lua_State* L) { const vconfig* vcfg = nullptr; const config& cfg = luaW_checkconfig(L, 1, vcfg); if(vcfg) { config clone_underlying = vcfg->get_config(); vconfig clone(clone_underlying); luaW_pushvconfig(L, clone); } else { luaW_pushconfig(L, cfg); } return 1; }
void lua_ai_context::set_persistent_data(const config &cfg) { int top = lua_gettop(L); lua_pushlightuserdata(L, static_cast<void *>(const_cast<char *>(&aisKey))); lua_rawget(L, LUA_REGISTRYINDEX); lua_rawgeti(L, -1, num_); luaW_pushconfig(L, cfg); lua_setfield(L, -2, "data"); lua_settop(L, top); }
/** * Parses a WML string into a config; does not preprocess or validate * - Arg 1: WML string * - Ret: config */ static int intf_parse_wml(lua_State* L) { std::string wml = luaL_checkstring(L, 1); std::string schema_path = luaL_optstring(L, 2, ""); std::shared_ptr<schema_validation::schema_validator> validator; if(!schema_path.empty()) { validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location(schema_path))); validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway } config result; read(result, wml, validator.get()); luaW_pushconfig(L, result); return 1; }
/** * Gets some data on a unit type (__index metamethod). * - Arg 1: table containing an "id" field. * - Arg 2: string containing the name of the property. * - Ret 1: something containing the attribute. */ static int impl_unit_type_get(lua_State *L) { const unit_type& ut = luaW_checkunittype(L, 1); char const *m = luaL_checkstring(L, 2); // Find the corresponding attribute. return_tstring_attrib("name", ut.type_name()); return_string_attrib("id", ut.id()); return_string_attrib("alignment", ut.alignment().to_string()); return_string_attrib("race", ut.race_id()); return_int_attrib("max_hitpoints", ut.hitpoints()); return_int_attrib("max_moves", ut.movement()); return_int_attrib("max_experience", ut.experience_needed()); return_int_attrib("cost", ut.cost()); return_int_attrib("level", ut.level()); return_int_attrib("recall_cost", ut.recall_cost()); return_cfgref_attrib("__cfg", ut.get_cfg()); if (strcmp(m, "traits") == 0) { lua_newtable(L); for (const config& trait : ut.possible_traits()) { const std::string& id = trait["id"]; lua_pushlstring(L, id.c_str(), id.length()); luaW_pushconfig(L, trait); lua_rawset(L, -3); } return 1; } if (strcmp(m, "abilities") == 0) { lua_push(L, ut.get_ability_list()); return 1; } if (strcmp(m, "attacks") == 0) { push_unit_attacks_table(L, 1); return 1; } // TODO: Should this only exist for base units? if(strcmp(m, "variations") == 0) { *new(L) const unit_type* = &ut; luaL_setmetatable(L, UnitTypeTable); return 1; } return 0; }
/** * Loads a WML file into a config * - Arg 1: WML file path * - Arg 2: (optional) Array of preprocessor defines, or false to skip preprocessing (true is also valid) * - Arg 3: (optional) Path to a schema file for validation (omit for no validation) * - Ret: config */ static int intf_load_wml(lua_State* L) { std::string file = luaL_checkstring(L, 1); bool preprocess = true; preproc_map defines_map; if(lua_type(L, 2) == LUA_TBOOLEAN) { preprocess = luaW_toboolean(L, 2); } else if(lua_type(L, 2) == LUA_TTABLE || lua_type(L, 2) == LUA_TUSERDATA) { lua_len(L, 2); int n = lua_tonumber(L, -1); lua_pop(L, 1); for(int i = 0; i < n; i++) { lua_geti(L, 2, i); if(!lua_isstring(L, -1)) { return luaL_argerror(L, 2, "expected bool or array of strings"); } std::string define = lua_tostring(L, -1); lua_pop(L, 1); if(!define.empty()) { defines_map.emplace(define, preproc_define(define)); } } } else if(!lua_isnoneornil(L, 2)) { return luaL_argerror(L, 2, "expected bool or array of strings"); } std::string schema_path = luaL_optstring(L, 3, ""); std::shared_ptr<schema_validation::schema_validator> validator; if(!schema_path.empty()) { validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location(schema_path))); validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway } std::string wml_file = filesystem::get_wml_location(file); filesystem::scoped_istream stream; config result; if(preprocess) { stream = preprocess_file(wml_file, &defines_map); } else { stream.reset(new std::ifstream(wml_file)); } read(result, *stream, validator.get()); luaW_pushconfig(L, result); return 1; }
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 }
void mapgen_lua_kernel::run_generator(const char * prog, const config & generator) { load_string(prog, boost::bind(&lua_kernel_base::throw_exception, this, _1, _2)); luaW_pushconfig(mState, generator); protected_call(1, 1, boost::bind(&lua_kernel_base::throw_exception, this, _1, _2)); }
typename boost::enable_if<typename boost::is_same<T, config>::type, void>::type lua_push(lua_State *L, const config& val) { luaW_pushconfig(L, val); }
static int cfun_ai_get_leader_goal(lua_State *L) { config goal = get_readonly_context(L).get_leader_goal(); luaW_pushconfig(L, goal); return 1; }
application_lua_kernel::request_list application_lua_kernel::thread::run_script(const plugins_context & ctxt, const std::vector<plugins_manager::event> & queue) { // There are two possibilities: (1) this is the first execution, and the C function is the only thing on the stack // (2) this is a subsequent execution, and there is nothing on the stack. // Either way we push the arguments to the function and call resume. // First we have to create the event table, by concatenating the event queue into a table. lua_newtable(T_); //this will be the event table for (std::size_t i = 0; i < queue.size(); ++i) { lua_newtable(T_); lua_pushstring(T_, queue[i].name.c_str()); lua_rawseti(T_, -2, 1); luaW_pushconfig(T_, queue[i].data); lua_rawseti(T_, -2, 2); lua_rawseti(T_, -2, i+1); } // Now we have to create the context object. It is arranged as a table of boost functions. std::shared_ptr<lua_context_backend> this_context_backend = std::make_shared<lua_context_backend> (lua_context_backend()); lua_newtable(T_); // this will be the context table for (const std::string & key : ctxt.callbacks_ | boost::adaptors::map_keys ) { lua_pushstring(T_, key.c_str()); lua_cpp::push_function(T_, std::bind(&impl_context_backend, _1, this_context_backend, key)); lua_settable(T_, -3); } // Now we have to create the info object (context accessors). It is arranged as a table of boost functions. lua_newtable(T_); // this will be the info table lua_pushstring(T_, "name"); lua_pushstring(T_, ctxt.name_.c_str()); lua_settable(T_, -3); for (const plugins_context::accessor_list::value_type & v : ctxt.accessors_) { const std::string & key = v.first; const plugins_context::accessor_function & func = v.second; lua_pushstring(T_, key.c_str()); lua_cpp::push_function(T_, std::bind(&impl_context_accessor, _1, this_context_backend, func)); lua_settable(T_, -3); } // Now we resume the function, calling the coroutine with the three arguments (events, context, info). lua_resume(T_, nullptr, 3); started_ = true; this_context_backend->valid = false; //invalidate the context object for lua if (lua_status(T_) != LUA_YIELD) { LOG_LUA << "Thread status = '" << lua_status(T_) << "'\n"; if (lua_status(T_) != LUA_OK) { std::stringstream ss; ss << "encountered a"; switch(lua_status(T_)) { case LUA_ERRSYNTAX: ss << " syntax "; break; case LUA_ERRRUN: ss << " runtime "; break; case LUA_ERRERR: ss << " error-handler "; break; default: ss << " "; break; } ss << "error:\n" << lua_tostring(T_, -1) << "\n"; ERR_LUA << ss.str() << std::endl; } } application_lua_kernel::request_list results; for (const plugins_manager::event & req : this_context_backend->requests) { results.push_back(std::bind(ctxt.callbacks_.find(req.name)->second, req.data)); //results.emplace_back(ctxt.callbacks_.find(req.name)->second, req.data); } return results; }