00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "configuration.hpp"
00023
00024 #include "../filesystem.hpp"
00025 #include "../foreach.hpp"
00026 #include "../log.hpp"
00027 #include "../serialization/parser.hpp"
00028 #include "../serialization/preprocessor.hpp"
00029 #include "../team.hpp"
00030
00031 #include <vector>
00032
00033 namespace ai {
00034
00035 static lg::log_domain log_ai_configuration("ai/config");
00036 #define DBG_AI_CONFIGURATION LOG_STREAM(debug, log_ai_configuration)
00037 #define LOG_AI_CONFIGURATION LOG_STREAM(info, log_ai_configuration)
00038 #define WRN_AI_CONFIGURATION LOG_STREAM(warn, log_ai_configuration)
00039 #define ERR_AI_CONFIGURATION LOG_STREAM(err, log_ai_configuration)
00040
00041
00042 class well_known_aspect {
00043 public:
00044 well_known_aspect(const std::string &name, bool attr = true)
00045 : name_(name),was_an_attribute_(attr)
00046 {
00047 }
00048
00049 virtual ~well_known_aspect() {};
00050
00051 std::string name_;
00052 bool was_an_attribute_;
00053 };
00054
00055 std::vector<well_known_aspect> well_known_aspects;
00056
00057 void configuration::init(const config &game_config)
00058 {
00059 ai_configurations_.clear();
00060 era_ai_configurations_.clear();
00061 well_known_aspects.clear();
00062 well_known_aspects.push_back(well_known_aspect("aggression"));
00063 well_known_aspects.push_back(well_known_aspect("attack_depth"));
00064 well_known_aspects.push_back(well_known_aspect("attacks"));
00065 well_known_aspects.push_back(well_known_aspect("avoid",false));
00066 well_known_aspects.push_back(well_known_aspect("caution"));
00067 well_known_aspects.push_back(well_known_aspect("grouping"));
00068 well_known_aspects.push_back(well_known_aspect("leader_aggression"));
00069 well_known_aspects.push_back(well_known_aspect("leader_goal",false));
00070 well_known_aspects.push_back(well_known_aspect("leader_value"));
00071 well_known_aspects.push_back(well_known_aspect("number_of_possible_recruits_to_force_recruit"));
00072 well_known_aspects.push_back(well_known_aspect("passive_leader"));
00073 well_known_aspects.push_back(well_known_aspect("passive_leader_shares_keep"));
00074
00075
00076
00077
00078 well_known_aspects.push_back(well_known_aspect("recruitment"));
00079 well_known_aspects.push_back(well_known_aspect("recruitment_ignore_bad_combat"));
00080 well_known_aspects.push_back(well_known_aspect("recruitment_ignore_bad_movement"));
00081 well_known_aspects.push_back(well_known_aspect("recruitment_pattern"));
00082 well_known_aspects.push_back(well_known_aspect("scout_village_targeting"));
00083 well_known_aspects.push_back(well_known_aspect("simple_targeting"));
00084 well_known_aspects.push_back(well_known_aspect("support_villages"));
00085 well_known_aspects.push_back(well_known_aspect("village_value"));
00086 well_known_aspects.push_back(well_known_aspect("villages_per_scout"));
00087
00088 const config &ais = game_config.child("ais");
00089 default_config_ = ais.child("default_config");
00090 if (!default_config_) {
00091 ERR_AI_CONFIGURATION << "Missing AI [default_config]. Therefore, default_config_ set to empty." << std::endl;
00092 default_config_ = config();
00093 }
00094
00095
00096 foreach (const config &ai_configuration, ais.child_range("ai")) {
00097 const std::string &id = ai_configuration["id"];
00098 if (id.empty()){
00099
00100 ERR_AI_CONFIGURATION << "skipped AI config due to missing id" << ". Config contains:"<< std::endl << ai_configuration << std::endl;
00101 continue;
00102 }
00103 if (ai_configurations_.count(id)>0){
00104 ERR_AI_CONFIGURATION << "skipped AI config due to duplicate id [" << id << "]. Config contains:"<< std::endl << ai_configuration << std::endl;
00105 continue;
00106 }
00107
00108 description desc;
00109 desc.id=id;
00110 desc.text = ai_configuration["description"].str();
00111 desc.cfg=ai_configuration;
00112
00113 ai_configurations_.insert(std::make_pair(id,desc));
00114 LOG_AI_CONFIGURATION << "loaded AI config: " << ai_configuration["description"] << std::endl;
00115 }
00116 }
00117
00118 void configuration::add_era_ai_from_config(const config &era)
00119 {
00120 era_ai_configurations_.clear();
00121 foreach (const config &ai_configuration, era.child_range("ai")) {
00122 const std::string &id = ai_configuration["id"];
00123 if (id.empty()){
00124
00125 ERR_AI_CONFIGURATION << "skipped AI config due to missing id" << ". Config contains:"<< std::endl << ai_configuration << std::endl;
00126 continue;
00127 }
00128 if (era_ai_configurations_.count(id)>0){
00129 ERR_AI_CONFIGURATION << "skipped AI config due to duplicate id [" << id << "]. Config contains:"<< std::endl << ai_configuration << std::endl;
00130 continue;
00131 }
00132
00133 description desc;
00134 desc.id=id;
00135 desc.text = ai_configuration["description"].str();
00136 desc.cfg=ai_configuration;
00137
00138 era_ai_configurations_.insert(std::make_pair(id,desc));
00139 LOG_AI_CONFIGURATION << "loaded AI config: " << ai_configuration["description"] << std::endl;
00140 }
00141 }
00142
00143 std::vector<description*> configuration::get_available_ais(){
00144 std::vector<description*> ais_list;
00145 for(description_map::iterator desc = ai_configurations_.begin(); desc!=ai_configurations_.end(); ++desc) {
00146 ais_list.push_back(&desc->second);
00147 DBG_AI_CONFIGURATION << "has ai with config: "<< std::endl << desc->second.cfg<< std::endl;
00148 }
00149 for(description_map::iterator desc = era_ai_configurations_.begin(); desc!=era_ai_configurations_.end(); ++desc) {
00150 ais_list.push_back(&desc->second);
00151 DBG_AI_CONFIGURATION << "has ai with config: "<< std::endl << desc->second.cfg<< std::endl;
00152 }
00153 return ais_list;
00154 }
00155
00156 const config& configuration::get_ai_config_for(const std::string &id)
00157 {
00158 description_map::iterator cfg_it = ai_configurations_.find(id);
00159 if (cfg_it==ai_configurations_.end()){
00160 description_map::iterator era_cfg_it = era_ai_configurations_.find(id);
00161 if (era_cfg_it==era_ai_configurations_.end()){
00162 return default_config_;
00163 } else {
00164 return era_cfg_it->second.cfg;
00165 }
00166 }
00167 return cfg_it->second.cfg;
00168 }
00169
00170
00171 configuration::description_map configuration::ai_configurations_ = configuration::description_map();
00172 configuration::description_map configuration::era_ai_configurations_ = configuration::description_map();
00173 config configuration::default_config_ = config();
00174
00175 bool configuration::get_side_config_from_file(const std::string& file, config& cfg ){
00176 try {
00177 scoped_istream stream = preprocess_file(get_wml_location(file));
00178 read(cfg, *stream);
00179 LOG_AI_CONFIGURATION << "Reading AI configuration from file '" << file << "'" << std::endl;
00180 } catch(config::error &) {
00181 ERR_AI_CONFIGURATION << "Error while reading AI configuration from file '" << file << "'" << std::endl;
00182 return false;
00183 }
00184 LOG_AI_CONFIGURATION << "Successfully read AI configuration from file '" << file << "'" << std::endl;
00185 return true;
00186 }
00187
00188 const config& configuration::get_default_ai_parameters()
00189 {
00190 return default_config_;
00191 }
00192
00193
00194 bool configuration::upgrade_aspect_config_from_1_07_02_to_1_07_03(side_number , const config& cfg, config& parsed_cfg, const std::string &id, bool aspect_was_attribute)
00195 {
00196 config aspect_config;
00197 aspect_config["id"] = id;
00198
00199 foreach (const config &aiparam, cfg.child_range("ai")) {
00200 const config &_aspect = aiparam.find_child("aspect","id",id);
00201 if (_aspect) {
00202 aspect_config.append(_aspect);
00203 }
00204
00205 if (aspect_was_attribute && !aiparam.has_attribute(id)) {
00206 continue;
00207 }
00208
00209 if (!aspect_was_attribute && !aiparam.child(id)) {
00210 continue;
00211 }
00212
00213 config facet_config;
00214 facet_config["engine"] = "cpp";
00215 facet_config["name"] = "standard_aspect";
00216 if (aspect_was_attribute) {
00217 facet_config["value"] = aiparam[id];
00218 } else {
00219 foreach (const config &value, aiparam.child_range(id)) {
00220 facet_config.add_child("value",value);
00221 }
00222 }
00223
00224 if (const config::attribute_value *v = aiparam.get("turns")) {
00225 facet_config["turns"] = *v;
00226 }
00227 if (const config::attribute_value *v = aiparam.get("time_of_day")) {
00228 facet_config["time_of_day"] = *v;
00229 }
00230
00231 aspect_config.add_child("facet",facet_config);
00232 }
00233
00234 parsed_cfg.add_child("aspect",aspect_config);
00235 return true;
00236 }
00237
00238
00239 bool configuration::parse_side_config(side_number side, const config& original_cfg, config &cfg )
00240 {
00241 LOG_AI_CONFIGURATION << "side "<< side <<": parsing AI configuration from config" << std::endl;
00242
00243
00244 cfg = config();
00245 foreach (const config &aiparam, original_cfg.child_range("ai")) {
00246 cfg.add_child("ai",aiparam);
00247 }
00248
00249
00250 if (const config::attribute_value *v = original_cfg.get("ai_algorithm")) {
00251 config ai_a;
00252 ai_a["ai_algorithm"] = *v;
00253 cfg.add_child("ai",ai_a);
00254 }
00255 DBG_AI_CONFIGURATION << "side " << side << ": config contains:"<< std::endl << cfg << std::endl;
00256
00257
00258 if (default_config_) {
00259 DBG_AI_CONFIGURATION << "side "<< side <<": applying default configuration" << std::endl;
00260 cfg.add_child_at("ai",default_config_,0);
00261 } else {
00262 ERR_AI_CONFIGURATION << "side "<< side <<": default configuration is not available, do not applying it" << std::endl;
00263 }
00264
00265
00266 int version = 10600;
00267 foreach (const config &aiparam, cfg.child_range("ai")) {
00268 if (const config::attribute_value *a = aiparam.get("version")){
00269 int v = a->to_int(version);
00270 if (version<v) {
00271 version = v;
00272 }
00273 }
00274 }
00275
00276 if (version<10703) {
00277 if (!upgrade_side_config_from_1_07_02_to_1_07_03(side, cfg)) {
00278 return false;
00279 }
00280 version = 10703;
00281 }
00282
00283
00284 if (version<10710) {
00285 version = 10710;
00286 }
00287
00288
00289 LOG_AI_CONFIGURATION << "side "<< side << ": doing final operations on AI config"<< std::endl;
00290 config parsed_cfg = config();
00291
00292 LOG_AI_CONFIGURATION << "side "<< side <<": merging AI configurations"<< std::endl;
00293 foreach (const config &aiparam, cfg.child_range("ai")) {
00294 parsed_cfg.append(aiparam);
00295 }
00296
00297 LOG_AI_CONFIGURATION << "side "<< side <<": setting config version to "<< version << std::endl;
00298 parsed_cfg["version"] = version;
00299
00300
00301 LOG_AI_CONFIGURATION << "side "<< side <<": merging AI aspect with the same id"<< std::endl;
00302 parsed_cfg.merge_children_by_attribute("aspect","id");
00303
00304 LOG_AI_CONFIGURATION << "side "<< side <<": removing duplicate [default] tags from aspects"<< std::endl;
00305 foreach (config &aspect_cfg, parsed_cfg.child_range("aspect")) {
00306 if (!aspect_cfg.child("default")) {
00307 WRN_AI_CONFIGURATION << "side "<< side <<": aspect with id=["<<aspect_cfg["id"]<<"] lacks default config facet!" <<std::endl;
00308 continue;
00309 }
00310 config c = aspect_cfg.child("default");
00311 aspect_cfg.clear_children("default");
00312 aspect_cfg.add_child("default",c);
00313 }
00314
00315 DBG_AI_CONFIGURATION << "side "<< side <<": done parsing side config, it contains:"<< std::endl << parsed_cfg << std::endl;
00316 LOG_AI_CONFIGURATION << "side "<< side <<": done parsing side config"<< std::endl;
00317
00318 cfg = parsed_cfg;
00319 return true;
00320
00321 }
00322
00323
00324 static void transfer_turns_and_time_of_day_data(const config &src, config &dst)
00325 {
00326 if (const config::attribute_value *turns = src.get("turns")) {
00327 dst["turns"] = *turns;
00328 }
00329 if (const config::attribute_value *time_of_day = src.get("time_of_day")) {
00330 dst["time_of_day"] = *time_of_day;
00331 }
00332 }
00333
00334
00335 bool configuration::upgrade_side_config_from_1_07_02_to_1_07_03(side_number side, config &cfg)
00336 {
00337 LOG_AI_CONFIGURATION << "side "<< side <<": upgrading ai config version from version 1.7.2 to 1.7.3"<< std::endl;
00338 config parsed_cfg;
00339
00340 bool is_idle_ai = false;
00341 if (cfg["ai_algorithm"]=="idle_ai") {
00342 is_idle_ai = true;
00343 } else {
00344 foreach (config &aiparam, cfg.child_range("ai")) {
00345 if (aiparam["ai_algorithm"]=="idle_ai") {
00346 is_idle_ai = true;
00347 break;
00348 }
00349 }
00350 }
00351
00352 if (!is_idle_ai) {
00353 parsed_cfg = get_ai_config_for("testing_ai_default");
00354 }
00355
00356
00357 upgrade_aspect_configs_from_1_07_02_to_1_07_03(side, cfg.child_range("ai"), parsed_cfg);
00358
00359
00360
00361 config fallback_stage_cfg_ai;
00362
00363 foreach (config &aiparam, cfg.child_range("ai")) {
00364 foreach (const well_known_aspect &wka, well_known_aspects) {
00365 if (wka.was_an_attribute_) {
00366 aiparam.remove_attribute(wka.name_);
00367 } else {
00368 aiparam.clear_children(wka.name_);
00369 }
00370 }
00371
00372
00373 foreach (const config &aitarget, aiparam.child_range("target")) {
00374 config aigoal;
00375 transfer_turns_and_time_of_day_data(aiparam,aigoal);
00376
00377 if (const config::attribute_value *v = aitarget.get("value")) {
00378 aigoal["value"] = *v;
00379 } else {
00380 aigoal["value"] = 0;
00381 }
00382
00383 config &aigoalcriteria = aigoal.add_child("criteria",aitarget);
00384 aigoalcriteria.remove_attribute("value");
00385
00386 parsed_cfg.add_child("goal",aigoal);
00387 }
00388 aiparam.clear_children("target");
00389
00390
00391 foreach (config &ai_protect_unit, aiparam.child_range("protect_unit")) {
00392 transfer_turns_and_time_of_day_data(aiparam,ai_protect_unit);
00393 upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side,ai_protect_unit,parsed_cfg,true);
00394 }
00395 aiparam.clear_children("protect_unit");
00396
00397
00398 foreach (config &ai_protect_location, aiparam.child_range("protect_location")) {
00399 transfer_turns_and_time_of_day_data(aiparam,ai_protect_location);
00400 upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side,ai_protect_location,parsed_cfg,false);
00401 }
00402 aiparam.clear_children("protect_location");
00403
00404
00405 if (const config::attribute_value *v = aiparam.get("protect_leader"))
00406 {
00407 config c;
00408 c["value"] = *v;
00409 c["canrecruit"] = true;
00410 c["side_number"] = side;
00411 transfer_turns_and_time_of_day_data(aiparam,c);
00412 if (const config::attribute_value *v = aiparam.get("protect_leader_radius")) {
00413 c["radius"] = *v;
00414 }
00415
00416 upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side,c,parsed_cfg,true);
00417 }
00418
00419 if (!aiparam.has_attribute("turns") && !aiparam.has_attribute("time_of_day")) {
00420 fallback_stage_cfg_ai.append(aiparam);
00421 }
00422 }
00423 fallback_stage_cfg_ai.clear_children("aspect");
00424
00425
00426 foreach (const config &aistage, fallback_stage_cfg_ai.child_range("stage")) {
00427 parsed_cfg.add_child("stage",aistage);
00428 }
00429 fallback_stage_cfg_ai.clear_children("stage");
00430
00431
00432 foreach (const config &aigoal, fallback_stage_cfg_ai.child_range("goal")) {
00433 parsed_cfg.add_child("goal",aigoal);
00434 }
00435 fallback_stage_cfg_ai.clear_children("goal");
00436
00437
00438 foreach (const config &aimodifyai, fallback_stage_cfg_ai.child_range("modify_ai")) {
00439 parsed_cfg.add_child("modify_ai",aimodifyai);
00440 }
00441 fallback_stage_cfg_ai.clear_children("modify_ai");
00442
00443
00444 cfg = config();
00445 cfg.add_child("ai",parsed_cfg);
00446 DBG_AI_CONFIGURATION << "side "<< side <<": after upgrade to 1.7.3 syntax, config contains:"<< std::endl << cfg << std::endl;
00447 return true;
00448 }
00449
00450
00451 void configuration::upgrade_aspect_configs_from_1_07_02_to_1_07_03(side_number side, const config::const_child_itors &ai_parameters, config &parsed_cfg)
00452 {
00453 config cfg;
00454
00455 foreach (const config &aiparam, ai_parameters) {
00456 cfg.add_child("ai",aiparam);
00457 }
00458
00459 DBG_AI_CONFIGURATION << "side "<< side <<": upgrading aspects from syntax of 1.7.2 to 1.7.3, old-style config is:" << std::endl << cfg << std::endl;
00460 foreach (const well_known_aspect &wka, well_known_aspects) {
00461 upgrade_aspect_config_from_1_07_02_to_1_07_03(side, cfg,parsed_cfg,wka.name_,wka.was_an_attribute_);
00462 }
00463 }
00464
00465
00466 void configuration::upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side_number side, const config &protect_cfg, config &parsed_cfg, bool add_filter)
00467 {
00468 config aigoal;
00469 aigoal["name"] = "protect";
00470 transfer_turns_and_time_of_day_data(protect_cfg,aigoal);
00471
00472 if (const config::attribute_value *v = protect_cfg.get("value")) {
00473 aigoal["value"] = *v;
00474 } else {
00475 aigoal["value"] = 1;
00476 }
00477
00478
00479 if (const config::attribute_value *v = protect_cfg.get("radius")) {
00480 aigoal["protect_radius"] = *v;
00481 } else {
00482 aigoal["protect_radius"] = 20;
00483 }
00484 DBG_AI_CONFIGURATION << "side "<< side <<": upgrading protect goal from syntax of 1.7.2 to 1.7.3, old-style config is:" << std::endl << protect_cfg << std::endl;
00485
00486
00487 if (add_filter) {
00488 config &aigoal_criteria = aigoal.add_child("criteria",config());
00489 config &aigoal_criteria_filter = aigoal_criteria.add_child("filter",protect_cfg);
00490 aigoal_criteria_filter.remove_attribute("value");
00491 aigoal_criteria_filter.remove_attribute("radius");
00492 } else {
00493 config &aigoal_criteria = aigoal.add_child("criteria",protect_cfg);
00494 aigoal_criteria.remove_attribute("value");
00495 aigoal_criteria.remove_attribute("radius");
00496 }
00497
00498
00499 parsed_cfg.add_child("goal",aigoal);
00500 DBG_AI_CONFIGURATION << "side "<< side <<": after upgrade of protect goal from syntax of 1.7.2 to 1.7.3, new-style config is:" << std::endl << aigoal << std::endl;
00501 }
00502
00503 }