Skip to content

Commit

Permalink
put [resource] before other content (again); fixes #3345
Browse files Browse the repository at this point in the history
Now content that is loaded via [load_resource] is placed to the position
where the [load_resource] was. This fixes a problem where previously one could
not use lua variables/functions created by the [resource][lua] because the
engine would put the [lua] tags from the [resource] after the [resource] from the
scenario.

This time it uses size_t indicies instad of vector iterators to prevent
possible bugs arisong from invalidating iterators when the size of the
vector changes.

This reverts commit b3e1680.

In the long run i think it might actually be better to allow [event] and
[lua] to have a order/priority attribute similar to lua on_event events.
Then this commit would probably not be needed anymore.
  • Loading branch information
gfgtdf committed Oct 18, 2018
1 parent 023b575 commit 7599746
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 24 deletions.
49 changes: 49 additions & 0 deletions src/config.cpp
Expand Up @@ -542,6 +542,55 @@ config& config::add_child_at(config_key_type key, const config& val, unsigned in
return *v[index];
}

size_t config::find_total_first_of(config_key_type key, size_t start)
{
assert(start <= ordered_children.size());
const size_t npos = static_cast<size_t>(-1);

auto pos = std::find_if(ordered_begin() + start, ordered_end(), [&](const config::any_child& can){ return can.key == key; });

if(pos == ordered_end()) {
return npos;
}

return static_cast<size_t>(pos - ordered_begin());
}

config& config::add_child_at_total(config_key_type key, const config &val, size_t pos)
{
assert(pos <= ordered_children.size());
if(pos == ordered_children.size()) {
//optimisation
config::add_child(key, val);
}

auto end = ordered_children.end();
auto pos_it = ordered_children.begin() + pos;
auto next = std::find_if(pos_it, end,[&](const child_pos& p){ return p.pos->first == key; });

if(next == end) {
config& res = config::add_child(key, val);
std::rotate(ordered_children.begin() + pos, ordered_children.end(), ordered_children.end());
return res;
}

auto pl = next->pos;
child_list& l = pl->second;
unsigned int index = next->index;
config& res = **(l.emplace(l.begin() + index, new config(val)));

for(auto ord = next; ord != end; ++ord) {
//this changes next->index and all later refernces to that tag.
if(ord->pos == pl) {
++ord->index;
}
}

//finally insert our new child in ordered_children.
ordered_children.insert(pos_it, { pl, index });
return res;
}

namespace
{
struct remove_ordered
Expand Down
7 changes: 6 additions & 1 deletion src/config.hpp
Expand Up @@ -624,7 +624,7 @@ class config
typedef std::vector<child_pos>::const_iterator Itor;
typedef const_all_children_iterator this_type;
explicit const_all_children_iterator(const Itor &i): i_(i) {}
const_all_children_iterator(all_children_iterator& i): i_(i.i_) {}
const_all_children_iterator(const all_children_iterator& i): i_(i.i_) {}

const_all_children_iterator &operator++() { ++i_; return *this; }
const_all_children_iterator operator++(int) { return const_all_children_iterator(i_++); }
Expand Down Expand Up @@ -659,6 +659,11 @@ class config
friend class config;
};

/// here pos is the index of the new child in _all_ childs, while in add_child_at
/// it is the index of the new child within all chils of type @key.
config& add_child_at_total(config_key_type key, const config &val, size_t pos);
size_t find_total_first_of(config_key_type key, size_t start = 0);

typedef boost::iterator_range<all_children_iterator> all_children_itors;
typedef boost::iterator_range<const_all_children_iterator> const_all_children_itors;

Expand Down
39 changes: 17 additions & 22 deletions src/saved_game.cpp
Expand Up @@ -298,7 +298,7 @@ struct modevents_entry

} // end anon namespace

void saved_game::load_mod(const std::string& type, const std::string& id)
void saved_game::load_mod(const std::string& type, const std::string& id, size_t pos)
{
if(const config& cfg = game_config_manager::get()->game_config().find_child(type, "id", id)) {
// Note the addon_id if this mod is required to play the game in mp.
Expand All @@ -323,18 +323,18 @@ void saved_game::load_mod(const std::string& type, const std::string& id)
if(modevent["enable_if"].empty()
|| variable_to_bool(carryover_.child_or_empty("variables"), modevent["enable_if"])
) {
this->starting_point_.add_child("event", modevent);
this->starting_point_.add_child_at_total("event", modevent, pos++);
}
}

// Copy lua
for(const config& modlua : cfg.child_range("lua")) {
this->starting_point_.add_child("lua", modlua);
this->starting_point_.add_child_at_total("lua", modlua, pos++);
}

// Copy load_resource
for(const config& load_resource : cfg.child_range("load_resource")) {
this->starting_point_.add_child("load_resource", load_resource);
this->starting_point_.add_child_at_total("load_resource", load_resource, pos++);
}
} else {
// TODO: A user message instead?
Expand Down Expand Up @@ -367,25 +367,20 @@ void saved_game::expand_mp_events()
mods.emplace_back("campaign", classification_.campaign);
}

// In the first iteration mod contains no [resource]s in all other iterations, mods contains only [resource]s.
do {
for(modevents_entry& mod : mods) {
load_mod(mod.type, mod.id);
}

mods.clear();

for(const config& cfg : starting_point_.child_range("load_resource")) {
if(loaded_resources.find(cfg["id"].str()) == loaded_resources.end()) {
mods.emplace_back("resource", cfg["id"].str());

loaded_resources.insert(cfg["id"].str());
}
for(modevents_entry& mod : mods) {
load_mod(mod.type, mod.id, starting_point_.all_children_count());
}
mods.clear();

while(starting_point_.has_child("load_resource")) {
std::string id = starting_point_.child("load_resource")["id"];
size_t pos = starting_point_.find_total_first_of("load_resource");
starting_point_.remove_child("load_resource", 0);
if(loaded_resources.find(id) == loaded_resources.end()) {
loaded_resources.insert(id);
load_mod("resource", id, pos);
}

starting_point_.clear_children("load_resource");
} while(!mods.empty());

}
this->starting_point_["has_mod_events"] = true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/saved_game.hpp
Expand Up @@ -72,7 +72,7 @@ class saved_game
/// should be called after expand_scenario() but before expand_carryover()
void expand_mp_events();
/// helper for expand_mp_events();
void load_mod(const std::string& type, const std::string& id);
void load_mod(const std::string& type, const std::string& id, size_t pos);
/// adds values of [option]s into [carryover_sides_start][variables] so that they are applied in the next level.
/// Note that since [variabels] are persistent we only use this once at the beginning
/// of a campaign but calling it multiple times is no harm eigher
Expand Down

0 comments on commit 7599746

Please sign in to comment.