00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "global.hpp"
00023
00024 #include "gamestatus.hpp"
00025 #include "log.hpp"
00026
00027 #include <cassert>
00028 #include <iostream>
00029
00030 #define LOG_NG LOG_STREAM(info, engine)
00031 #define WRN_NG LOG_STREAM(warn, engine)
00032 #define ERR_NG LOG_STREAM(err, engine)
00033
00034 namespace
00035 {
00036
00037
00038
00039
00040 game_state* repos = NULL;
00041
00042
00043 std::map<config const *, int> config_cache;
00044
00045
00046 std::map<std::string const *, config const *> hash_to_cache;
00047
00048
00049 std::map<config const *, std::string const *> config_hashes;
00050
00051 config empty_config;
00052
00053 struct compare_str_ptr {
00054 bool operator()(const std::string* s1, const std::string* s2) const
00055 {
00056 return (*s1) < (*s2);
00057 }
00058 };
00059
00060 class hash_memory_manager {
00061 public:
00062 const std::string *find(const std::string& str) const {
00063 std::set<std::string const*, compare_str_ptr>::const_iterator itor = mem_.lower_bound(&str);
00064 if(itor == mem_.end() || **itor != str) {
00065 return NULL;
00066 }
00067 return *itor;
00068 }
00069 void insert(const std::string *newhash) {
00070 mem_.insert(newhash);
00071 }
00072 void clear() {
00073 hash_to_cache.clear();
00074 config_hashes.clear();
00075 std::set<std::string const*, compare_str_ptr>::iterator mem_it,
00076 mem_end = mem_.end();
00077 for(mem_it = mem_.begin(); mem_it != mem_end; ++mem_it) {
00078 delete *mem_it;
00079 }
00080 mem_.clear();
00081 }
00082 ~hash_memory_manager() {
00083 clear();
00084 }
00085 private:
00086 std::set<std::string const*, compare_str_ptr> mem_;
00087 };
00088 hash_memory_manager hash_memory;
00089 }
00090
00091 static const std::string* get_hash_of(const config* cp) {
00092
00093 std::map<config const *, std::string const *>::iterator ch_it = config_hashes.find(cp);
00094 if(ch_it != config_hashes.end()) {
00095 return ch_it->second;
00096 }
00097
00098 const std::string & temp_hash = cp->hash();
00099 std::string const* find_hash = hash_memory.find(temp_hash);
00100 if(find_hash != NULL) {
00101 return find_hash;
00102 }
00103
00104 std::string* new_hash = new std::string(temp_hash);
00105 hash_memory.insert(new_hash);
00106
00107 return new_hash;
00108 }
00109
00110 static void increment_config_usage(const config*& key) {
00111 if(key == NULL) return;
00112 std::map<config const *, int>::iterator this_usage = config_cache.find(key);
00113 if(this_usage != config_cache.end()) {
00114 ++this_usage->second;
00115 return;
00116 }
00117 const std::string *hash = get_hash_of(key);
00118 const config *& cfg_store = hash_to_cache[hash];
00119 if(cfg_store == NULL || (key != cfg_store && *key != *cfg_store)) {
00120
00121 key = new config(*key);
00122
00123 cfg_store = key;
00124
00125 config_hashes[key] = hash;
00126 } else {
00127
00128 key = cfg_store;
00129 }
00130 ++(config_cache[key]);
00131 }
00132
00133 static void decrement_config_usage(const config* key) {
00134 if(key == NULL) return;
00135 std::map<config const *, int>::iterator this_usage = config_cache.find(key);
00136 assert(this_usage != config_cache.end());
00137 if(--(this_usage->second) == 0) {
00138 config_cache.erase(this_usage);
00139 if(config_cache.empty()) {
00140 hash_memory.clear();
00141 } else {
00142 if(!hash_to_cache.empty()) {
00143 hash_to_cache.erase(get_hash_of(key));
00144 }
00145 config_hashes.erase(key);
00146 }
00147 delete key;
00148 }
00149 }
00150
00151 vconfig::vconfig() :
00152 cfg_(NULL), cache_key_(NULL)
00153 {
00154 }
00155
00156 vconfig::vconfig(const config* cfg, const config * cache_key) :
00157 cfg_(cfg), cache_key_(cache_key)
00158 {
00159 increment_config_usage(cache_key_);
00160 if(cache_key_ != cache_key) {
00161
00162 cfg_ = cache_key_;
00163 }
00164 }
00165
00166 vconfig::vconfig(const vconfig& v) :
00167 cfg_(v.cfg_), cache_key_(v.cache_key_)
00168 {
00169 increment_config_usage(cache_key_);
00170 }
00171
00172 vconfig::~vconfig()
00173 {
00174 decrement_config_usage(cache_key_);
00175 }
00176
00177 vconfig& vconfig::operator=(const vconfig cfg)
00178 {
00179 const config* prev_key = cache_key_;
00180 cfg_ = cfg.cfg_;
00181 cache_key_ = cfg.cache_key_;
00182 increment_config_usage(cache_key_);
00183 decrement_config_usage(prev_key);
00184 return *this;
00185 }
00186
00187 vconfig& vconfig::operator=(const config* cfg)
00188 {
00189 if(cfg_ != cfg) {
00190 cfg_ = cfg;
00191 decrement_config_usage(cache_key_);
00192 cache_key_ = NULL;
00193 }
00194 return *this;
00195 }
00196
00197 const config vconfig::get_parsed_config() const
00198 {
00199 config res;
00200
00201 for(string_map::const_iterator itor = cfg_->values.begin();
00202 itor != cfg_->values.end(); ++itor)
00203 {
00204 res[itor->first] = expand(itor->first);
00205 }
00206
00207 for(config::all_children_iterator child = cfg_->ordered_begin();
00208 child != cfg_->ordered_end(); ++child)
00209 {
00210 const std::string &child_key = *(*child).first;
00211 if(child_key == "insert_tag") {
00212 vconfig insert_cfg(child->second);
00213 const t_string& name = insert_cfg["name"];
00214 const t_string& vname = insert_cfg["variable"];
00215 if(!recursion_.insert(vname).second) {
00216 ERR_NG << "vconfig::get_parsed_config() infinite recursion detected, aborting"
00217 << std::endl;
00218 res.add_child("insert_tag", insert_cfg.get_config());
00219 return res;
00220 }
00221 variable_info vinfo(vname, false, variable_info::TYPE_CONTAINER);
00222 if(!vinfo.is_valid) {
00223 res.add_child(name);
00224 } else if(vinfo.explicit_index) {
00225 res.add_child(name, vconfig(&(vinfo.as_container())).get_parsed_config());
00226 } else {
00227 variable_info::array_range range = vinfo.as_array();
00228 if(range.first == range.second) {
00229 res.add_child(name);
00230 }
00231 while(range.first != range.second) {
00232 res.add_child(name, vconfig(*range.first++).get_parsed_config());
00233 }
00234 }
00235 recursion_.erase(vname);
00236 } else {
00237 res.add_child(child_key, vconfig((*child).second).get_parsed_config());
00238 }
00239 }
00240 return res;
00241 }
00242
00243 vconfig::child_list vconfig::get_children(const std::string& key) const
00244 {
00245 vconfig::child_list res;
00246
00247 for(config::all_children_iterator child = cfg_->ordered_begin();
00248 child != cfg_->ordered_end(); ++child)
00249 {
00250 const std::string &child_key = *(*child).first;
00251 if(child_key == key) {
00252 res.push_back(vconfig(child->second, cache_key_));
00253 } else if(child_key == "insert_tag") {
00254 vconfig insert_cfg(child->second);
00255 if(insert_cfg["name"] == key) {
00256 variable_info vinfo(insert_cfg["variable"], false, variable_info::TYPE_CONTAINER);
00257 if(!vinfo.is_valid) {
00258
00259 res.push_back(vconfig(&empty_config));
00260 } else if(vinfo.explicit_index) {
00261 config * cp = &(vinfo.as_container());
00262 res.push_back(vconfig(cp, cp));
00263 } else {
00264 variable_info::array_range range = vinfo.as_array();
00265 if(range.first == range.second) {
00266
00267 res.push_back(vconfig(&empty_config));
00268 }
00269 while(range.first != range.second) {
00270 config * cp = *range.first++;
00271 res.push_back(vconfig(cp, cp));
00272 }
00273 }
00274 }
00275 }
00276 }
00277 return res;
00278 }
00279
00280 vconfig vconfig::child(const std::string& key) const
00281 {
00282 const config *natural = cfg_->child(key);
00283 if(natural)
00284 {
00285 return vconfig(natural, cache_key_);
00286 }
00287 for(config::const_child_itors chitors = cfg_->child_range("insert_tag");
00288 chitors.first != chitors.second; ++chitors.first)
00289 {
00290 vconfig insert_cfg(*chitors.first);
00291 if(insert_cfg["name"] == key) {
00292 variable_info vinfo(insert_cfg["variable"], false, variable_info::TYPE_CONTAINER);
00293 if(!vinfo.is_valid) {
00294 return vconfig(&empty_config);
00295 }
00296 config * cp = &(vinfo.as_container());
00297 return vconfig(cp, cp);
00298 }
00299 }
00300 return vconfig();
00301 }
00302
00303 bool vconfig::has_child(const std::string& key) const
00304 {
00305 if(cfg_->child(key) != NULL) {
00306 return true;
00307 }
00308 for(config::const_child_itors chitors = cfg_->child_range("insert_tag");
00309 chitors.first != chitors.second; ++chitors.first)
00310 {
00311 vconfig insert_cfg(*chitors.first);
00312 if(insert_cfg["name"] == key) {
00313 return true;
00314 }
00315 }
00316 return false;
00317 }
00318
00319 const t_string vconfig::expand(const std::string& key) const
00320 {
00321 const t_string& val = (*cfg_)[key];
00322 if(repos != NULL && !val.str().empty()) {
00323 std::string interp = utils::interpolate_variables_into_string(val.str(), *repos);
00324 if(val.str() != interp) {
00325 return t_string(interp);
00326 }
00327 }
00328 return t_string(val);
00329 }
00330
00331 vconfig::all_children_iterator::all_children_iterator(config::all_children_iterator i)
00332 : i_(i), inner_index_(0), index_offset_(0)
00333 {
00334 }
00335
00336 vconfig::all_children_iterator& vconfig::all_children_iterator::operator++()
00337 {
00338 if(i_.get_key() == "insert_tag") {
00339 variable_info vinfo(vconfig(&i_.get_child())["variable"], false, variable_info::TYPE_CONTAINER);
00340 if(vinfo.is_valid && !vinfo.explicit_index) {
00341 variable_info::array_range range = vinfo.as_array();
00342 if(range.first != range.second && range.first + (++inner_index_) != range.second) {
00343 ++index_offset_;
00344 return *this;
00345 }
00346 }
00347 }
00348 ++i_;
00349 inner_index_ = 0;
00350 return *this;
00351 }
00352
00353 vconfig::all_children_iterator vconfig::all_children_iterator::operator++(int)
00354 {
00355 vconfig::all_children_iterator i = *this;
00356 this->operator++();
00357 return i;
00358 }
00359
00360 std::pair<const std::string,const vconfig> vconfig::all_children_iterator::operator*() const
00361 {
00362 return std::make_pair<const std::string, const vconfig>(get_key(), get_child());
00363 }
00364
00365 vconfig::all_children_iterator::pointer vconfig::all_children_iterator::operator->() const
00366 {
00367 return pointer(new std::pair<const std::string, const vconfig>(get_key(), get_child()));
00368 }
00369
00370 const std::string vconfig::all_children_iterator::get_key() const
00371 {
00372 const std::string& key = i_.get_key();
00373 if(key == "insert_tag") {
00374 return vconfig(&i_.get_child())["name"];
00375 }
00376 return key;
00377 }
00378
00379 const vconfig vconfig::all_children_iterator::get_child() const
00380 {
00381 if(i_.get_key() == "insert_tag") {
00382 config * cp;
00383 variable_info vinfo(vconfig(&i_.get_child())["variable"], false, variable_info::TYPE_CONTAINER);
00384 if(!vinfo.is_valid) {
00385 return vconfig(&empty_config);
00386 } else if(inner_index_ == 0) {
00387 cp = &(vinfo.as_container());
00388 return vconfig(cp, cp);
00389 }
00390 cp = *(vinfo.as_array().first + inner_index_);
00391 return vconfig(cp, cp);
00392 }
00393 return vconfig(&i_.get_child());
00394 }
00395
00396 size_t vconfig::all_children_iterator::get_index() const
00397 {
00398 return i_.get_index() + index_offset_;
00399 }
00400
00401 bool vconfig::all_children_iterator::operator==(all_children_iterator i) const
00402 {
00403 return (i_ == i.i_ && inner_index_ == i.inner_index_);
00404 }
00405
00406 bool vconfig::all_children_iterator::operator!=(all_children_iterator i) const
00407 {
00408 return (i_ != i.i_ || inner_index_ != i.inner_index_);
00409 }
00410
00411 vconfig::all_children_iterator vconfig::ordered_begin() const
00412 {
00413 return all_children_iterator(cfg_->ordered_begin());
00414 }
00415
00416 vconfig::all_children_iterator vconfig::ordered_end() const
00417 {
00418 return all_children_iterator(cfg_->ordered_end());
00419 }
00420
00421 namespace variable
00422 {
00423 manager::manager(game_state* repository)
00424 {
00425 repos = repository;
00426 }
00427
00428 manager::~manager()
00429 {
00430 repos = NULL;
00431 hash_memory.clear();
00432 }
00433 }
00434
00435 scoped_wml_variable::scoped_wml_variable(const std::string& var_name)
00436 : var_name_(var_name), activated_(false)
00437 {
00438 repos->scoped_variables.push_back(this);
00439 }
00440
00441 void scoped_wml_variable::store(const config& var_value)
00442 {
00443 const config::child_list& children = repos->get_variables().get_children(var_name_);
00444 for(config::child_list::const_iterator i = children.begin(); i != children.end(); ++i) {
00445 previous_val_.append(**i);
00446 }
00447 repos->clear_variable_cfg(var_name_);
00448 repos->add_variable_cfg(var_name_, var_value);
00449 activated_ = true;
00450 }
00451
00452 scoped_wml_variable::~scoped_wml_variable()
00453 {
00454 if(activated_) {
00455 repos->clear_variable_cfg(var_name_);
00456 config::child_list old_val =previous_val_.get_children(var_name_);
00457 for(config::child_list::iterator j=old_val.begin(); j != old_val.end() ; j++){
00458 repos->add_variable_cfg(var_name_,**j);
00459 }
00460 }
00461 assert(repos->scoped_variables.back() == this);
00462 repos->scoped_variables.pop_back();
00463 }
00464
00465 void scoped_xy_unit::activate()
00466 {
00467 unit_map::const_iterator itor = umap_.find(gamemap::location(x_,y_));
00468 if(itor != umap_.end()) {
00469 config tmp_cfg;
00470 itor->second.write(tmp_cfg);
00471 tmp_cfg["x"] = lexical_cast<std::string,int>(x_ + 1);
00472 tmp_cfg["y"] = lexical_cast<std::string,int>(y_ + 1);
00473 store(tmp_cfg);
00474 } else {
00475 ERR_NG << "failed to auto-store $" << name() << " at (" << x_ << ',' << y_ << ")\n";
00476 }
00477 }
00478
00479 void scoped_recall_unit::activate()
00480 {
00481 player_info* const player = repos->get_player(player_);
00482 if(player != NULL) {
00483 if(player->available_units.size() > recall_index_) {
00484 config tmp_cfg;
00485 player->available_units[recall_index_].write(tmp_cfg);
00486 tmp_cfg["x"] = "recall";
00487 tmp_cfg["y"] = "recall";
00488 store(tmp_cfg);
00489 } else {
00490 ERR_NG << "failed to auto-store $" << name() << " for player: " << player_
00491 << " at recall index: " << recall_index_ << '\n';
00492 }
00493 } else {
00494 ERR_NG << "failed to auto-store $" << name() << " for player: " << player_ << '\n';
00495 }
00496 }
00497
00498 namespace {
00499 bool recursive_activation = false;
00500
00501
00502 void activate_scope_variable(std::string var_name)
00503 {
00504 if(recursive_activation)
00505 return;
00506 const std::string::iterator itor = std::find(var_name.begin(),var_name.end(),'.');
00507 if(itor != var_name.end()) {
00508 var_name.erase(itor, var_name.end());
00509 }
00510 std::vector<scoped_wml_variable*>::reverse_iterator rit;
00511 for(rit = repos->scoped_variables.rbegin(); rit != repos->scoped_variables.rend(); ++rit) {
00512 if((**rit).name() == var_name) {
00513 recursive_activation = true;
00514 if(!(**rit).activated()) {
00515 (**rit).activate();
00516 }
00517 recursive_activation = false;
00518 break;
00519 }
00520 }
00521 }
00522 }
00523
00524 variable_info::variable_info(const std::string& varname, bool force_valid, TYPE validation_type)
00525 : vartype(validation_type), is_valid(false), explicit_index(false), index(0), vars(NULL)
00526 {
00527 assert(repos != NULL);
00528 activate_scope_variable(varname);
00529
00530 vars = &repos->variables;
00531 key = varname;
00532 std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
00533 int dot_index = key.find('.');
00534
00535 while(itor != key.end()) {
00536 std::string element=key.substr(0,dot_index);
00537 key = key.substr(dot_index+1);
00538
00539 size_t inner_index = 0;
00540 const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
00541 const bool inner_explicit_index = index_start != element.end();
00542 if(inner_explicit_index) {
00543 const std::string::iterator index_end = std::find(index_start,element.end(),']');
00544 const std::string index_str(index_start+1,index_end);
00545 inner_index = static_cast<size_t>(lexical_cast_default<int>(index_str));
00546 if(inner_index > game_config::max_loop) {
00547 ERR_NG << "variable_info: index greater than " << game_config::max_loop
00548 << ", truncated\n";
00549 inner_index = game_config::max_loop;
00550 }
00551 element = std::string(element.begin(),index_start);
00552 }
00553
00554 size_t size = vars->get_children(element).size();
00555 if(size <= inner_index) {
00556 if(force_valid) {
00557
00558 if(inner_explicit_index || key != "length") {
00559 for(; size <= inner_index; ++size) {
00560 vars->add_child(element);
00561 }
00562 }
00563 } else if(inner_explicit_index) {
00564 WRN_NG << "variable_info: invalid WML array index, "
00565 << varname << std::endl;
00566 return;
00567 } else if(key != "length") {
00568 WRN_NG << "variable_info: retrieving member of non-existant WML container, "
00569 << varname << std::endl;
00570 return;
00571 }
00572 }
00573 if(!inner_explicit_index && key == "length") {
00574 switch(vartype) {
00575 case variable_info::TYPE_ARRAY:
00576 case variable_info::TYPE_CONTAINER:
00577 WRN_NG << "variable_info: using reserved WML variable as wrong type, "
00578 << varname << std::endl;
00579 is_valid = force_valid || repos->temporaries.child(varname) != NULL;
00580 break;
00581 case variable_info::TYPE_SCALAR:
00582 default:
00583
00584 repos->temporaries[varname] = lexical_cast<std::string>(size);
00585 is_valid = true;
00586 break;
00587 }
00588 key = varname;
00589 vars = &repos->temporaries;
00590 return;
00591 }
00592
00593
00594 vars = vars->get_children(element)[inner_index];
00595 itor = std::find(key.begin(),key.end(),'.');
00596 dot_index = key.find('.');
00597 }
00598
00599 const std::string::iterator index_start = std::find(key.begin(),key.end(),'[');
00600 explicit_index = index_start != key.end();
00601 if(explicit_index) {
00602 const std::string::iterator index_end = std::find(index_start,key.end(),']');
00603 const std::string index_str(index_start+1,index_end);
00604 index = static_cast<size_t>(lexical_cast_default<int>(index_str));
00605 if(index > game_config::max_loop) {
00606 ERR_NG << "variable_info: index greater than " << game_config::max_loop
00607 << ", truncated\n";
00608 index = game_config::max_loop;
00609 }
00610 key = std::string(key.begin(),index_start);
00611 size_t size = vars->get_children(key).size();
00612 if(size <= index) {
00613 if(!force_valid) {
00614 WRN_NG << "variable_info: invalid WML array index, " << varname << std::endl;
00615 return;
00616 }
00617 for(; size <= index; ++size) {
00618 vars->add_child(key);
00619 }
00620 }
00621 switch(vartype) {
00622 case variable_info::TYPE_ARRAY:
00623 vars = vars->get_children(key)[index];
00624 key = "__array";
00625 is_valid = force_valid || vars->child(key) != NULL;
00626 break;
00627 case variable_info::TYPE_SCALAR:
00628 vars = vars->get_children(key)[index];
00629 key = "__value";
00630 is_valid = force_valid || vars->has_attribute(key);
00631 break;
00632 case variable_info::TYPE_CONTAINER:
00633 case variable_info::TYPE_UNSPECIFIED:
00634 default:
00635 is_valid = true;
00636 return;
00637 }
00638 WRN_NG << "variable_info: using explicitly indexed Container as wrong WML type, "
00639 << varname << std::endl;
00640 explicit_index = false;
00641 index = 0;
00642 } else {
00643
00644 switch(vartype) {
00645 case variable_info::TYPE_ARRAY:
00646 case variable_info::TYPE_CONTAINER:
00647 is_valid = force_valid || vars->child(key);
00648 break;
00649 case variable_info::TYPE_SCALAR:
00650 is_valid = force_valid || vars->has_attribute(key);
00651 break;
00652 case variable_info::TYPE_UNSPECIFIED:
00653 default:
00654 is_valid = true;
00655 break;
00656 }
00657 }
00658 }
00659
00660 t_string& variable_info::as_scalar() {
00661 assert(is_valid);
00662 return vars->values[key];
00663 }
00664
00665 config& variable_info::as_container() {
00666 assert(is_valid);
00667 if(explicit_index) {
00668
00669 return *vars->get_children(key)[index];
00670 }
00671 config *temp = vars->child(key);
00672 if(temp) {
00673
00674 return *temp;
00675 }
00676
00677 return vars->add_child(key);
00678 }
00679
00680 variable_info::array_range variable_info::as_array() {
00681 assert(is_valid);
00682 return vars->child_range(key);
00683 }