From 9e7dc5ba008298d823c13cff214f7477601b5efd Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 13 Jun 2014 16:41:20 -0400 Subject: [PATCH] unit_map, lua, team recall lists use reference counted UnitPtr Defines a UnitPtr (boost::intrusive_ptr, after irc discussion), which the engine will use to pass units between different modules, and which it is planned that the animation engine will also hold, to avoid segfaulting. Unfortunately this commit could not really be made smaller, it is necessary to change all of these things over at once, or specify very complicated deletion policies for the units at the boundaries of the modules. The main intention of the commit is to get these three modules using a reference counting system to hold units, even as they are passed between the modules. Eventually the fake units and other kinds of units will all also be held in such pointers, and the unit_map::unit_pod object will be replaced itself with a single smart pointer. Finally the animations objects will hold weak pointers to units, to fix the segfault issues. This commit required us to change over the whiteboard, most of the action_wml, and the AI modules, since these make use of the recall list from the team class. We also add the unit_ptr.hpp header file, to allow to forward declare the UnitPtr object essentially, and it's const variation. If we forward declare the intrusive_ptr functions, we can forward declare the UnitPtr type and avoid including unit in a bunch of places that we don't need to. (Good as that is a very heavy include.) The declaration is now in unit_ptr.hpp Since we can't forward declare inheritance, the easiest way to resolve linker problems is to not derive unit from the reference_counted_object class and just include the intrusive_ptr boilerplate as usual instead. --- src/actions/create.cpp | 82 ++++++++++------- src/actions/create.hpp | 17 ++-- src/actions/move.cpp | 2 +- src/actions/undo.cpp | 52 ++++++----- src/actions/undo.hpp | 19 ++-- src/ai/actions.cpp | 4 +- src/ai/composite/engine_lua.cpp | 4 +- src/ai/contexts.cpp | 4 +- src/ai/contexts.hpp | 8 +- src/ai/default/ai.cpp | 5 +- src/ai/default/attack.cpp | 2 +- src/ai/formula/ai.cpp | 4 +- src/ai/lua/core.cpp | 4 +- src/ai/recruitment/recruitment.cpp | 30 +++--- src/carryover.cpp | 8 +- src/dialogs.cpp | 27 +++--- src/dialogs.hpp | 9 +- src/game_board.cpp | 35 +++---- src/game_board.hpp | 9 +- src/game_events/action_wml.cpp | 62 ++++++------- src/game_events/conditional_wml.cpp | 6 +- src/game_preferences.cpp | 4 +- src/gamestatus.cpp | 3 +- src/gui/dialogs/gamestate_inspector.cpp | 20 ++-- src/menu_events.cpp | 4 +- src/mouse_events.cpp | 8 +- src/scripting/lua.cpp | 101 ++++++++++----------- src/scripting/lua_api.cpp | 33 ++++--- src/scripting/lua_api.hpp | 18 ++-- src/side_filter.cpp | 9 +- src/synced_commands.cpp | 2 +- src/team.hpp | 6 +- src/tests/test_unit_map.cpp | 12 +-- src/tests/test_whiteboard_side_actions.cpp | 2 +- src/unit.cpp | 39 ++++++-- src/unit.hpp | 18 ++-- src/unit_map.cpp | 44 ++++----- src/unit_map.hpp | 25 ++--- src/unit_ptr.hpp | 32 +++++++ src/variable.cpp | 2 +- src/whiteboard/action.cpp | 2 +- src/whiteboard/action.hpp | 2 +- src/whiteboard/highlighter.cpp | 12 +-- src/whiteboard/highlighter.hpp | 6 +- src/whiteboard/manager.cpp | 4 +- src/whiteboard/mapbuilder.cpp | 18 ++-- src/whiteboard/move.cpp | 6 +- src/whiteboard/move.hpp | 2 +- src/whiteboard/recall.cpp | 22 ++--- src/whiteboard/recall.hpp | 4 +- src/whiteboard/recruit.cpp | 8 +- src/whiteboard/recruit.hpp | 6 +- src/whiteboard/side_actions.cpp | 16 ++-- src/whiteboard/suppose_dead.cpp | 10 +- src/whiteboard/suppose_dead.hpp | 2 +- src/whiteboard/utility.cpp | 12 +-- src/whiteboard/utility.hpp | 2 +- 57 files changed, 496 insertions(+), 413 deletions(-) create mode 100644 src/unit_ptr.hpp diff --git a/src/actions/create.cpp b/src/actions/create.cpp index 40042d591d5b..fc123697098e 100644 --- a/src/actions/create.cpp +++ b/src/actions/create.cpp @@ -41,6 +41,7 @@ #include "../synced_checkup.hpp" #include "../synced_context.hpp" #include "../team.hpp" +#include "../unit.hpp" #include "../unit_display.hpp" #include "../variable.hpp" #include "../whiteboard/manager.hpp" @@ -189,10 +190,11 @@ void unit_creator::add_unit(const config &cfg, const vconfig* vcfg) bool animate = temp_cfg["animate"].to_bool(); temp_cfg.remove_attribute("animate"); - std::vector &recall_list = team_.recall_list(); - std::vector::iterator recall_list_element = find_if_matches_id(recall_list, id); + std::vector &recall_list = team_.recall_list(); + std::vector::iterator recall_list_it = find_if_matches_id(recall_list, id); + UnitPtr & recall_list_element = *recall_list_it; - if ( recall_list_element == recall_list.end() ) { + if ( recall_list_it == recall_list.end() ) { //make a temporary unit boost::scoped_ptr temp_unit(new unit(temp_cfg, true, vcfg)); map_location loc = find_location(temp_cfg, temp_unit.get()); @@ -206,7 +208,8 @@ void unit_creator::add_unit(const config &cfg, const vconfig* vcfg) else if ( add_to_recall_ ) { //add to recall list unit *new_unit = temp_unit.get(); - recall_list.push_back(*new_unit); + UnitPtr temp_ptr = UnitPtr(new unit(*new_unit)); + recall_list.push_back(temp_ptr); DBG_NG << "inserting unit with id=["<side() << "\n"; preferences::encountered_units().insert(new_unit->type_id()); } @@ -286,6 +289,12 @@ bool can_recruit_from(const map_location& leader_loc, int side) != map_location::null_location(); } +bool can_recruit_from(const unit& leader) +{ + return can_recruit_from(leader.get_location(), leader.side()); +} + + /** * Checks to see if a leader at @a leader_loc could recruit on @a recruit_loc. * This takes into account terrain, shroud (for side @a side), and whether or @@ -328,6 +337,11 @@ bool can_recruit_on(const map_location& leader_loc, const map_location& recruit_ return !rt.steps.empty(); } +bool can_recruit_on(const unit& leader, const map_location& recruit_loc) +{ + return can_recruit_on(leader.get_location(), recruit_loc, leader.side()); +} + namespace actions { @@ -402,26 +416,29 @@ namespace { // Helpers for get_recalls() * that can be skipped (because they are already in @a result), and the * underlying ID of units added to @a result will be added to @a already_added. */ - void add_leader_filtered_recalls(const unit & leader, - std::vector & result, + void add_leader_filtered_recalls(const UnitConstPtr leader, + std::vector< UnitConstPtr > & result, std::set * already_added = NULL) { - const team& leader_team = (*resources::teams)[leader.side()-1]; - const std::vector& recall_list = leader_team.recall_list(); + const team& leader_team = (*resources::teams)[leader->side()-1]; + const std::vector& recall_list = leader_team.recall_list(); const std::string& save_id = leader_team.save_id(); - BOOST_FOREACH(const unit& recall_unit, recall_list) + BOOST_FOREACH(const UnitConstPtr & recall_unit_ptr, recall_list) { + const unit & recall_unit = *recall_unit_ptr; // Do not add a unit twice. size_t underlying_id = recall_unit.underlying_id(); if ( !already_added || already_added->count(underlying_id) == 0 ) { // Only units that match the leader's recall filter are valid. - scoped_recall_unit this_unit("this_unit", save_id, &recall_unit - &recall_list[0]); + const std::vector::const_iterator rit = find_if_matches_id(recall_list, recall_unit.id()); + + scoped_recall_unit this_unit("this_unit", save_id, rit - recall_list.begin()); - if ( recall_unit.matches_filter(vconfig(leader.recall_filter()), map_location::null_location()) ) + if ( recall_unit.matches_filter(vconfig(leader->recall_filter()), map_location::null_location()) ) { - result.push_back(&recall_unit); + result.push_back(recall_unit_ptr); if ( already_added != NULL ) already_added->insert(underlying_id); } @@ -430,11 +447,11 @@ namespace { // Helpers for get_recalls() } }// anonymous namespace -const std::vector get_recalls(int side, const map_location &recall_loc) +std::vector get_recalls(int side, const map_location &recall_loc) { LOG_NG << "getting recall list for side " << side << " at location " << recall_loc << "\n"; - std::vector result; + std::vector result; /* * We have three use cases: @@ -449,14 +466,14 @@ const std::vector get_recalls(int side, const map_location &recall_ // Check for a leader at recall_loc (means we are recalling from there, // rather than to there). - unit_map::const_iterator find_it = resources::units->find(recall_loc); + const unit_map::const_iterator find_it = resources::units->find(recall_loc); if ( find_it != resources::units->end() ) { if ( find_it->can_recruit() && find_it->side() == side && resources::gameboard->map().is_keep(recall_loc) ) { // We have been requested to get the recalls for this // particular leader. - add_leader_filtered_recalls(*find_it, result); + add_leader_filtered_recalls(find_it.get_shared_ptr(), result); return result; } else if ( find_it->is_visible_to_team((*resources::teams)[side-1], resources::gameboard->map(), false) ) @@ -482,17 +499,17 @@ const std::vector get_recalls(int side, const map_location &recall_ continue; leader_in_place= true; - add_leader_filtered_recalls(*u, result, &valid_local_recalls); + add_leader_filtered_recalls(u.get_shared_ptr(), result, &valid_local_recalls); } } if ( !leader_in_place ) { // Return the full recall list. - const std::vector& recall_list = (*resources::teams)[side-1].recall_list(); - BOOST_FOREACH(const unit &recall, recall_list) + const std::vector< UnitPtr >& recall_list = (*resources::teams)[side-1].recall_list(); + BOOST_FOREACH(const UnitConstPtr & recall, recall_list) { - result.push_back(&recall); + result.push_back(recall); } } @@ -515,9 +532,10 @@ namespace { // Helpers for check_recall_location() return RECRUIT_NO_LEADER; // Make sure the recalling unit can recall this specific unit. - const team& recall_team = (*resources::teams)[recaller.side()-1]; + team& recall_team = (*resources::teams)[recaller.side()-1]; + std::vector::iterator it = find_if_matches_id(recall_team.recall_list(), recall_unit.id()); scoped_recall_unit this_unit("this_unit", recall_team.save_id(), - &recall_unit - &recall_team.recall_list()[0]); + it - recall_team.recall_list().begin()); if ( !recall_unit.matches_filter(vconfig(recaller.recall_filter()), map_location::null_location()) ) return RECRUIT_NO_ABLE_LEADER; @@ -966,12 +984,12 @@ bool place_recruit(const unit &u, const map_location &recruit_location, const ma void recruit_unit(const unit_type & u_type, int side_num, const map_location & loc, const map_location & from, bool show, bool use_undo) { - const unit new_unit(u_type, side_num, true); + const UnitPtr new_unit = UnitPtr( new unit(u_type, side_num, true)); // Place the recruit. - bool mutated = place_recruit(new_unit, loc, from, u_type.cost(), false, show); - statistics::recruit_unit(new_unit); + bool mutated = place_recruit(*new_unit, loc, from, u_type.cost(), false, show); + statistics::recruit_unit(*new_unit); // To speed things a bit, don't bother with the undo stack during // an AI turn. The AI will not undo nor delay shroud updates. @@ -999,16 +1017,16 @@ bool recall_unit(const std::string & id, team & current_team, const map_location & loc, const map_location & from, bool show, bool use_undo) { - std::vector & recall_list = current_team.recall_list(); + std::vector & recall_list = current_team.recall_list(); // Find the unit to recall. - std::vector::iterator recall_it = find_if_matches_id(recall_list, id); + std::vector::iterator recall_it = find_if_matches_id(recall_list, id); if ( recall_it == recall_list.end() ) return false; // Make a copy of the unit before erasing it from the list. - unit recall(*recall_it); + UnitPtr recall(*recall_it); recall_list.erase(recall_it); // ** IMPORTANT: id might become invalid at this point! // (Use recall.id() instead, if needed.) @@ -1017,15 +1035,15 @@ bool recall_unit(const std::string & id, team & current_team, // We also check to see if a custom unit level recall has been set if not, // we use the team's recall cost otherwise the unit's. bool mutated; - if (recall.recall_cost() < 0) { - mutated = place_recruit(recall, loc, from, current_team.recall_cost(), + if (recall->recall_cost() < 0) { + mutated = place_recruit(*recall, loc, from, current_team.recall_cost(), true, show); } else { - mutated = place_recruit(recall, loc, from, recall.recall_cost(), + mutated = place_recruit(*recall, loc, from, recall->recall_cost(), true, show); } - statistics::recall_unit(recall); + statistics::recall_unit(*recall); // To speed things a bit, don't bother with the undo stack during // an AI turn. The AI will not undo nor delay shroud updates. diff --git a/src/actions/create.hpp b/src/actions/create.hpp index 1d09dff18d62..ce1940b59517 100644 --- a/src/actions/create.hpp +++ b/src/actions/create.hpp @@ -21,12 +21,13 @@ #ifndef ACTIONS_CREATE_H_INCLUDED #define ACTIONS_CREATE_H_INCLUDED -class config; -class team; -class vconfig; +class config; +class team; +class unit_type; +class vconfig; #include "../map_location.hpp" -#include "../unit.hpp" +#include "../unit_ptr.hpp" class unit_creator { @@ -71,16 +72,14 @@ class unit_creator { bool can_recruit_from(const map_location& leader_loc, int side); /// Checks to see if @a leader (assumed a leader) can recruit somewhere. /// This takes into account terrain, shroud, and the presence of visible units. -inline bool can_recruit_from(const unit& leader) -{ return can_recruit_from(leader.get_location(), leader.side()); } +bool can_recruit_from(const unit& leader); /// Checks to see if a leader at @a leader_loc could recruit on @a recruit_loc. bool can_recruit_on(const map_location& leader_loc, const map_location& recruit_loc, int side); /// Checks to see if @a leader (assumed a leader) can recruit on @a recruit_loc. /// This takes into account terrain, shroud, and whether or not there is already /// a visible unit at recruit_loc. -inline bool can_recruit_on(const unit& leader, const map_location& recruit_loc) -{ return can_recruit_on(leader.get_location(), recruit_loc, leader.side()); } +bool can_recruit_on(const unit& leader, const map_location& recruit_loc); namespace actions { @@ -190,7 +189,7 @@ const std::set get_recruits(int side, const map_location &recruit_l * @param recall_loc the hex field being part of the castle the player wants to recruit on or from. * @return a set of units that can be recalled by @a side on (or from) @a recall_loc or the full recall list of @a side. */ -const std::vector get_recalls(int side, const map_location &recall_loc); +std::vector get_recalls(int side, const map_location &recall_loc); /** * Place a unit into the game. diff --git a/src/actions/move.cpp b/src/actions/move.cpp index 117efdfe5fa7..ec380d36c7f6 100644 --- a/src/actions/move.cpp +++ b/src/actions/move.cpp @@ -1073,7 +1073,7 @@ namespace { // Private helpers for move_unit() if ( mover_valid ) { // MP_COUNTDOWN: added param undo_stack->add_move( - *move_it_, begin_, real_end_, orig_moves_, + move_it_.get_shared_ptr(), begin_, real_end_, orig_moves_, action_time_bonus, orig_village_owner, orig_dir_); } diff --git a/src/actions/undo.cpp b/src/actions/undo.cpp index f6301b0f2f05..de4fbee213ce 100644 --- a/src/actions/undo.cpp +++ b/src/actions/undo.cpp @@ -56,14 +56,14 @@ undo_list::undo_action::~undo_action() struct undo_list::dismiss_action : undo_list::undo_action { - unit dismissed_unit; + UnitPtr dismissed_unit; - explicit dismiss_action(const unit& dismissed) : undo_action(), - dismissed_unit(dismissed) + explicit dismiss_action(const UnitConstPtr dismissed) : undo_action(), + dismissed_unit(new unit(*dismissed)) {} explicit dismiss_action(const config & unit_cfg) : undo_action(), - dismissed_unit(unit_cfg) + dismissed_unit(new unit(unit_cfg)) {} virtual ~dismiss_action(); @@ -86,7 +86,7 @@ struct undo_list::move_action : undo_list::undo_action { map_location goto_hex; - move_action(const unit& moved, + move_action(const UnitConstPtr moved, const std::vector::const_iterator & begin, const std::vector::const_iterator & end, int sm, int timebonus, int orig, const map_location::DIRECTION dir) : @@ -94,8 +94,8 @@ struct undo_list::move_action : undo_list::undo_action { starting_moves(sm), original_village_owner(orig), countdown_time_bonus(timebonus), - starting_dir(dir == map_location::NDIRECTIONS ? moved.facing() : dir), - goto_hex(moved.get_goto()) + starting_dir(dir == map_location::NDIRECTIONS ? moved->facing() : dir), + goto_hex(moved->get_goto()) {} move_action(const config & unit_cfg, const config & route_cfg, int sm, int timebonus, int orig, const map_location::DIRECTION dir) : @@ -127,10 +127,10 @@ struct undo_list::recall_action : undo_list::undo_action { map_location recall_from; - recall_action(const unit& recalled, const map_location& loc, + recall_action(const UnitConstPtr recalled, const map_location& loc, const map_location& from) : undo_action(recalled, loc), - id(recalled.id()), + id(recalled->id()), recall_from(from) {} recall_action(const config & unit_cfg, const map_location & loc, @@ -157,10 +157,10 @@ struct undo_list::recruit_action : undo_list::undo_action { map_location recruit_from; - recruit_action(const unit& recruited, const map_location& loc, + recruit_action(const UnitConstPtr recruited, const map_location& loc, const map_location& from) : undo_action(recruited, loc), - u_type(recruited.type()), + u_type(recruited->type()), recruit_from(from) {} recruit_action(const config & unit_cfg, const unit_type & type, @@ -291,7 +291,7 @@ void undo_list::dismiss_action::write(config & cfg) const { cfg.add_child("replay_data", replay_data); cfg["type"] = "dismiss"; - dismissed_unit.write(cfg.add_child("unit")); + dismissed_unit->write(cfg.add_child("unit")); } /** @@ -399,7 +399,7 @@ void undo_list::add_auto_shroud(bool turned_on) /** * Adds a dismissal to the undo stack. */ -void undo_list::add_dismissal(const unit & u) +void undo_list::add_dismissal(const UnitConstPtr u) { add(new dismiss_action(u)); } @@ -407,7 +407,7 @@ void undo_list::add_dismissal(const unit & u) /** * Adds a move to the undo stack. */ -void undo_list::add_move(const unit& u, +void undo_list::add_move(const UnitConstPtr u, const std::vector::const_iterator & begin, const std::vector::const_iterator & end, int start_moves, int timebonus, int village_owner, @@ -419,7 +419,7 @@ void undo_list::add_move(const unit& u, /** * Adds a recall to the undo stack. */ -void undo_list::add_recall(const unit& u, const map_location& loc, +void undo_list::add_recall(const UnitConstPtr u, const map_location& loc, const map_location& from) { add(new recall_action(u, loc, from)); @@ -428,7 +428,7 @@ void undo_list::add_recall(const unit& u, const map_location& loc, /** * Adds a recruit to the undo stack. */ -void undo_list::add_recruit(const unit& u, const map_location& loc, +void undo_list::add_recruit(const UnitConstPtr u, const map_location& loc, const map_location& from) { add(new recruit_action(u, loc, from)); @@ -648,9 +648,13 @@ bool undo_list::recall_action::undo(int side, undo_list & /*undos*/) return false; } - const unit &un = *un_it; - statistics::un_recall_unit(un); - int cost = statistics::un_recall_unit_cost(un); + UnitPtr un = un_it.get_shared_ptr(); + if (!un) { + return false; + } + + statistics::un_recall_unit(*un); + int cost = statistics::un_recall_unit_cost(*un); if (cost < 0) { current_team.spend_gold(-current_team.recall_cost()); } @@ -829,9 +833,7 @@ bool undo_list::dismiss_action::redo(int side) } recorder.redo(replay_data); replay_data.clear(); - std::vector::iterator unit_it = - find_if_matches_id(current_team.recall_list(), dismissed_unit.id()); - current_team.recall_list().erase(unit_it); + erase_if_matches_id(current_team.recall_list(), dismissed_unit->id()); return true; } @@ -853,15 +855,15 @@ bool undo_list::recall_action::redo(int side) map_location loc = route.front(); map_location from = recall_from; - const std::vector & recalls = current_team.recall_list(); - std::vector::const_iterator unit_it = find_if_matches_id(recalls, id); + const std::vector & recalls = current_team.recall_list(); + std::vector::const_iterator unit_it = find_if_matches_id(recalls, id); if ( unit_it == recalls.end() ) { ERR_NG << "Trying to redo a recall of '" << id << "', but that unit is not in the recall list."; return false; } - const std::string &msg = find_recall_location(side, loc, from, *unit_it); + const std::string &msg = find_recall_location(side, loc, from, **unit_it); if ( msg.empty() ) { recorder.redo(replay_data); replay_data.clear(); diff --git a/src/actions/undo.hpp b/src/actions/undo.hpp index 4f0d8a61b049..6e740296fa45 100644 --- a/src/actions/undo.hpp +++ b/src/actions/undo.hpp @@ -22,13 +22,12 @@ #include "vision.hpp" #include "../map_location.hpp" +#include "../unit_ptr.hpp" #include #include #include -class unit; - namespace actions { @@ -39,18 +38,18 @@ class undo_list : boost::noncopyable { /// Each type of action gets its own derived type. struct undo_action : boost::noncopyable { /// Constructor for move actions. - undo_action(const unit& u, + undo_action(const UnitConstPtr u, const std::vector::const_iterator & begin, const std::vector::const_iterator & end) : route(begin, end), - view_info(new clearer_info(u)) + view_info(new clearer_info(*u)) { } /// Constructor for recruit and recall actions. /// These types of actions are guaranteed to have a non-empty route. - undo_action(const unit& u, const map_location& loc) : + undo_action(const UnitConstPtr u, const map_location& loc) : route(1, loc), - view_info(new clearer_info(u)) + view_info(new clearer_info(*u)) {} /// Constructor from a config storing the view info. /// Does not set @a route. @@ -125,18 +124,18 @@ class undo_list : boost::noncopyable { /// Adds an auto-shroud toggle to the undo stack. void add_auto_shroud(bool turned_on); /// Adds a dismissal to the undo stack. - void add_dismissal(const unit & u); + void add_dismissal(const UnitConstPtr u); /// Adds a move to the undo stack. - void add_move(const unit& u, + void add_move(const UnitConstPtr u, const std::vector::const_iterator & begin, const std::vector::const_iterator & end, int start_moves, int timebonus=0, int village_owner=-1, const map_location::DIRECTION dir=map_location::NDIRECTIONS); /// Adds a recall to the undo stack. - void add_recall(const unit& u, const map_location& loc, + void add_recall(const UnitConstPtr u, const map_location& loc, const map_location& from); /// Adds a recruit to the undo stack. - void add_recruit(const unit& u, const map_location& loc, + void add_recruit(const UnitConstPtr u, const map_location& loc, const map_location& from); private: /// Adds a shroud update to the undo stack. diff --git a/src/ai/actions.cpp b/src/ai/actions.cpp index 0ffb4c8ce23f..8ecb3483c364 100644 --- a/src/ai/actions.cpp +++ b/src/ai/actions.cpp @@ -501,12 +501,12 @@ recall_result::recall_result(side_number side, const unit * recall_result::get_recall_unit(const team &my_team) { - const std::vector::const_iterator rec = find_if_matches_id(my_team.recall_list(), unit_id_); + const std::vector::const_iterator rec = find_if_matches_id(my_team.recall_list(), unit_id_); if (rec == my_team.recall_list().end()) { set_error(E_NOT_AVAILABLE_FOR_RECALLING); return NULL; } - return &*rec; + return rec->get(); } bool recall_result::test_enough_gold(const team &my_team) diff --git a/src/ai/composite/engine_lua.cpp b/src/ai/composite/engine_lua.cpp index ca407ae4eef8..6dcd71c5cd90 100644 --- a/src/ai/composite/engine_lua.cpp +++ b/src/ai/composite/engine_lua.cpp @@ -168,7 +168,7 @@ class lua_sticky_candidate_action_wrapper : public lua_candidate_action_wrapper , bound_unit_() { map_location loc(cfg["unit_x"] - 1, cfg["unit_y"] - 1); // lua and c++ coords differ by one - bound_unit_ = boost::shared_ptr(new unit(*resources::units->find(loc))); + bound_unit_ = UnitPtr(new unit(*resources::units->find(loc))); } virtual double evaluate() @@ -190,7 +190,7 @@ class lua_sticky_candidate_action_wrapper : public lua_candidate_action_wrapper this->disable(); // we do not want to execute the same sticky CA twice -> will be moved out to Lua later } private: - boost::shared_ptr bound_unit_; + UnitPtr bound_unit_; }; diff --git a/src/ai/contexts.cpp b/src/ai/contexts.cpp index 3a3595d1a4b9..143971dc8186 100644 --- a/src/ai/contexts.cpp +++ b/src/ai/contexts.cpp @@ -775,9 +775,9 @@ const moves_map& readonly_context_impl::get_possible_moves() const } -const std::vector& readonly_context_impl::get_recall_list() const +const std::vector& readonly_context_impl::get_recall_list() const { - static std::vector dummy_units; + static std::vector dummy_units; ///@todo 1.9: check for (level_["disallow_recall"])) if(!current_team().persistent()) { return dummy_units; diff --git a/src/ai/contexts.hpp b/src/ai/contexts.hpp index b51bbd35393c..c36f7a157274 100644 --- a/src/ai/contexts.hpp +++ b/src/ai/contexts.hpp @@ -25,7 +25,7 @@ #include "../generic_event.hpp" #include "../config.hpp" #include "lua/unit_advancements_aspect.hpp" - +#include "../unit_ptr.hpp" //#include "../unit.hpp" @@ -298,7 +298,7 @@ class readonly_context : public virtual side_context { virtual const moves_map& get_possible_moves() const = 0; - virtual const std::vector& get_recall_list() const = 0; + virtual const std::vector& get_recall_list() const = 0; virtual stage_ptr get_recruitment(ai_context &context) const = 0; @@ -819,7 +819,7 @@ class readonly_context_proxy : public virtual readonly_context, public virtual s } - virtual const std::vector& get_recall_list() const + virtual const std::vector& get_recall_list() const { return target_->get_recall_list(); } @@ -1427,7 +1427,7 @@ class readonly_context_impl : public virtual side_context_proxy, public readonly virtual const moves_map& get_possible_moves() const; - virtual const std::vector& get_recall_list() const; + virtual const std::vector& get_recall_list() const; virtual stage_ptr get_recruitment(ai_context &context) const; diff --git a/src/ai/default/ai.cpp b/src/ai/default/ai.cpp index 42d29fc82bba..b12af4413619 100644 --- a/src/ai/default/ai.cpp +++ b/src/ai/default/ai.cpp @@ -655,7 +655,8 @@ class unit_combat_score_getter { : stage_(s) { } - std::pair operator()(const unit &u) { + std::pair operator()(const UnitPtr u_ptr) { + const unit & u = *u_ptr; std::pair p; p.first = u.id(); const unit_type& u_type = u.type(); @@ -761,7 +762,7 @@ bool ai_default_recruitment_stage::analyze_recall_list() return false; } - const std::vector &recalls = current_team().recall_list(); + const std::vector &recalls = current_team().recall_list(); if (recalls.empty()) { return false; diff --git a/src/ai/default/attack.cpp b/src/ai/default/attack.cpp index 0193cd2dea69..874242d272da 100644 --- a/src/ai/default/attack.cpp +++ b/src/ai/default/attack.cpp @@ -96,7 +96,7 @@ void attack_analysis::analyze(const gamemap& map, unit_map& units, for (m = movements.begin(); m != movements.end(); ++m) { // We fix up units map to reflect what this would look like. - unit *up = units.extract(m->first); + UnitPtr up = units.extract(m->first); up->set_location(m->second); units.insert(up); double m_aggression = aggression; diff --git a/src/ai/formula/ai.cpp b/src/ai/formula/ai.cpp index 8d118467cc09..ef6b1ab25aa6 100644 --- a/src/ai/formula/ai.cpp +++ b/src/ai/formula/ai.cpp @@ -810,8 +810,8 @@ variant formula_ai::get_value(const std::string& key) const { std::vector tmp; - for(std::vector::const_iterator i = current_team().recall_list().begin(); i != current_team().recall_list().end(); ++i) { - tmp.push_back( variant( new unit_callable(*i) ) ); + for(std::vector::const_iterator i = current_team().recall_list().begin(); i != current_team().recall_list().end(); ++i) { + tmp.push_back( variant( new unit_callable(**i) ) ); } return variant( &tmp ); diff --git a/src/ai/lua/core.cpp b/src/ai/lua/core.cpp index 8e00634f0dea..ec4262a63624 100644 --- a/src/ai/lua/core.cpp +++ b/src/ai/lua/core.cpp @@ -119,7 +119,7 @@ static bool to_map_location(lua_State *L, int &index, map_location &res) { if (lua_isuserdata(L, index)) { - unit const *u = luaW_tounit(L, index); + const UnitConstPtr u = luaW_tounit(L, index); if (!u) return false; res = u->get_location(); ++index; @@ -142,7 +142,7 @@ static int cfun_ai_get_suitable_keep(lua_State *L) int index = 1; ai::readonly_context &context = get_readonly_context(L); - unit const *leader; + UnitConstPtr leader; if (lua_isuserdata(L, index)) { leader = luaW_tounit(L, index); diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 7ace0030e496..f141a18c09d4 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -248,15 +248,15 @@ void recruitment::execute() { // Add recalls. // Recalls are treated as recruits. While recruiting // we'll check if we can do a recall instead of a recruitment. - BOOST_FOREACH(const unit& recall, current_team().recall_list()) { + BOOST_FOREACH(const UnitConstPtr & recall, current_team().recall_list()) { // Check if this leader is allowed to recall this unit. vconfig filter = vconfig(leader->recall_filter()); - if (!recall.matches_filter(filter, map_location::null_location())) { + if (!recall->matches_filter(filter, map_location::null_location())) { continue; } - data.recruits.insert(recall.type_id()); - data.scores[recall.type_id()] = 0.0; - global_recruits.insert(recall.type_id()); + data.recruits.insert(recall->type_id()); + data.scores[recall->type_id()] = 0.0; + global_recruits.insert(recall->type_id()); } // Check if leader is in danger. (If a enemies unit can attack the leader) @@ -470,19 +470,19 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type, const data& leader_data) const { const std::string* best_recall_id = NULL; double best_recall_value = -1; - BOOST_FOREACH(const unit& recall_unit, current_team().recall_list()) { - if (type != recall_unit.type_id()) { + BOOST_FOREACH(const UnitConstPtr & recall_unit, current_team().recall_list()) { + if (type != recall_unit->type_id()) { continue; } // Check if this leader is allowed to recall this unit. vconfig filter = vconfig(leader_data.leader->recall_filter()); - if (!recall_unit.matches_filter(filter, map_location::null_location())) { - LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit.id() << "\n"; + if (!recall_unit->matches_filter(filter, map_location::null_location())) { + LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n"; continue; } double average_cost_of_advanced_unit = 0; int counter = 0; - BOOST_FOREACH(const std::string& advancement, recall_unit.advances_to()) { + BOOST_FOREACH(const std::string& advancement, recall_unit->advances_to()) { const unit_type* advancement_type = unit_types.find(advancement); if (!advancement_type) { continue; @@ -494,16 +494,16 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type, average_cost_of_advanced_unit /= counter; } else { // Unit don't have advancements. Use cost of unit itself. - average_cost_of_advanced_unit = recall_unit.cost(); + average_cost_of_advanced_unit = recall_unit->cost(); } - double xp_quantity = static_cast(recall_unit.experience()) / - recall_unit.max_experience(); - double recall_value = recall_unit.cost() + xp_quantity * average_cost_of_advanced_unit; + double xp_quantity = static_cast(recall_unit->experience()) / + recall_unit->max_experience(); + double recall_value = recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit; if (recall_value < current_team().recall_cost()) { continue; // Unit is not worth to get recalled. } if (recall_value > best_recall_value) { - best_recall_id = &recall_unit.id(); + best_recall_id = &recall_unit->id(); best_recall_value = recall_value; } } diff --git a/src/carryover.cpp b/src/carryover.cpp index 621408353d0f..a9ca7d38bdd9 100644 --- a/src/carryover.cpp +++ b/src/carryover.cpp @@ -53,9 +53,9 @@ carryover::carryover(const team& t, const int gold, const bool add) , recall_list_() , save_id_(t.save_id()) { - BOOST_FOREACH(const unit& u, t.recall_list()) { + BOOST_FOREACH(const UnitConstPtr & u, t.recall_list()) { recall_list_.push_back(config()); - u.write(recall_list_.back()); + u->write(recall_list_.back()); } } @@ -110,9 +110,9 @@ void carryover::update_carryover(const team& t, const int gold, const bool add){ current_player_ = t.current_player(); name_ = t.name(); previous_recruits_.insert(t.recruits().begin(), t.recruits().end()); - BOOST_FOREACH(const unit& u, t.recall_list()) { + BOOST_FOREACH(const UnitConstPtr & u, t.recall_list()) { recall_list_.push_back(config()); - u.write(recall_list_.back()); + u->write(recall_list_.back()); } } diff --git a/src/dialogs.cpp b/src/dialogs.cpp index ae3d0d2e439b..c4ea94aa3928 100644 --- a/src/dialogs.cpp +++ b/src/dialogs.cpp @@ -85,20 +85,21 @@ namespace class delete_recall_unit : public gui::dialog_button_action { public: - delete_recall_unit(display& disp, gui::filter_textbox& filter, const std::vector& units) : disp_(disp), filter_(filter), units_(units) {} + delete_recall_unit(display& disp, gui::filter_textbox& filter, const std::vector& units) : disp_(disp), filter_(filter), units_(units) {} private: gui::dialog_button_action::RESULT button_pressed(int menu_selection); display& disp_; gui::filter_textbox& filter_; - const std::vector& units_; + const std::vector& units_; }; gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_selection) { const size_t index = size_t(filter_.get_index(menu_selection)); if(index < units_.size()) { - const unit &u = *(units_[index]); + const UnitConstPtr & u_ptr = units_[index]; + const unit & u = *u_ptr; //If the unit is of level > 1, or is close to advancing, //we warn the player about it @@ -127,17 +128,17 @@ gui::dialog_button_action::RESULT delete_recall_unit::button_pressed(int menu_se // Remove the item from filter_textbox memory filter_.delete_item(menu_selection); //add dismissal to the undo stack - resources::undo_stack->add_dismissal(u); + resources::undo_stack->add_dismissal(u_ptr); // Find the unit in the recall list. - std::vector& recall_list = (*resources::teams)[u.side() -1].recall_list(); + std::vector& recall_list = (*resources::teams)[u.side() -1].recall_list(); assert(!recall_list.empty()); - std::vector::iterator dismissed_unit = + std::vector::iterator dismissed_unit = find_if_matches_id(recall_list, u.id()); assert(dismissed_unit != recall_list.end()); // Record the dismissal, then delete the unit. - synced_context::run_in_synced_context("disband", replay_helper::get_disband(dismissed_unit->id())); + synced_context::run_in_synced_context("disband", replay_helper::get_disband((*dismissed_unit)->id())); //recorder.add_disband(dismissed_unit->id()); //recall_list.erase(dismissed_unit); @@ -441,9 +442,9 @@ int recruit_dialog(display& disp, std::vector< const unit_type* >& units, const #ifdef LOW_MEM -int recall_dialog(display& disp, std::vector< const unit* >& units, int /*side*/, const std::string& title_suffix, const int team_recall_cost) +int recall_dialog(display& disp, std::vector< UnitConstPtr >& units, int /*side*/, const std::string& title_suffix, const int team_recall_cost) #else -int recall_dialog(display& disp, std::vector< const unit* >& units, int side, const std::string& title_suffix, const int team_recall_cost) +int recall_dialog(display& disp, std::vector< UnitConstPtr >& units, int side, const std::string& title_suffix, const int team_recall_cost) #endif { std::vector options, options_to_filter; @@ -462,7 +463,7 @@ int recall_dialog(display& disp, std::vector< const unit* >& units, int side, co options.push_back(heading.str()); options_to_filter.push_back(options.back()); - BOOST_FOREACH(const unit* u, units) + BOOST_FOREACH(const UnitConstPtr & u, units) { std::stringstream option, option_to_filter; std::string name = u->name(); @@ -1207,13 +1208,13 @@ void unit_preview_pane::draw_contents() } } -units_list_preview_pane::units_list_preview_pane(const unit *u, TYPE type, bool on_left_side) : +units_list_preview_pane::units_list_preview_pane(UnitConstPtr u, TYPE type, bool on_left_side) : unit_preview_pane(NULL, type, on_left_side), units_(1, u) { } -units_list_preview_pane::units_list_preview_pane(const std::vector &units, +units_list_preview_pane::units_list_preview_pane(const std::vector &units, const gui::filter_textbox* filter, TYPE type, bool on_left_side) : unit_preview_pane(filter, type, on_left_side), units_(units) @@ -1226,7 +1227,7 @@ units_list_preview_pane::units_list_preview_pane(const std::vector &units, units_(units.size()) { for (unsigned i = 0; i < units.size(); ++i) - units_[i] = &units[i]; + units_[i] = UnitConstPtr (new unit(units[i])); } size_t units_list_preview_pane::size() const diff --git a/src/dialogs.hpp b/src/dialogs.hpp index aa2d5ffc9b2c..fcd758cb52f0 100644 --- a/src/dialogs.hpp +++ b/src/dialogs.hpp @@ -26,6 +26,7 @@ class terrain_type; #include "map_location.hpp" #include "construct_dialog.hpp" #include "network.hpp" +#include "unit_ptr.hpp" #include "ai/lua/unit_advancements_aspect.hpp" namespace dialogs { @@ -59,7 +60,7 @@ std::string load_game_dialog(display& disp, const config& terrain_config, bool* int recruit_dialog(display& disp, std::vector& units, const std::vector& items, int side, const std::string& title_suffix); -int recall_dialog(display& disp, std::vector& units, int side, const std::string& title_suffix, const int team_recall_cost); +int recall_dialog(display& disp, std::vector& units, int side, const std::string& title_suffix, const int team_recall_cost); /** Show unit-stats in a side-pane to unit-list, recall-list, etc. */ class unit_preview_pane : public gui::preview_pane @@ -110,8 +111,8 @@ class unit_preview_pane : public gui::preview_pane class units_list_preview_pane : public dialogs::unit_preview_pane { public: - units_list_preview_pane(const unit *u, TYPE type = SHOW_ALL, bool left_side = true); - units_list_preview_pane(const std::vector &units, + units_list_preview_pane(UnitConstPtr u, TYPE type = SHOW_ALL, bool left_side = true); + units_list_preview_pane(const std::vector &units, const gui::filter_textbox *filter = NULL, TYPE type = SHOW_ALL, bool left_side = true); units_list_preview_pane(const std::vector &units, @@ -123,7 +124,7 @@ class units_list_preview_pane : public dialogs::unit_preview_pane const details get_details() const; void process_event(); - std::vector units_; + std::vector units_; }; diff --git a/src/game_board.cpp b/src/game_board.cpp index 01e01f23accc..4180384272ba 100644 --- a/src/game_board.cpp +++ b/src/game_board.cpp @@ -74,12 +74,13 @@ void game_board::set_all_units_user_end_turn() { } void game_board::all_survivors_to_recall() { - BOOST_FOREACH (unit & un, units_) { - if (teams_[un.side() - 1].persistent()) { - un.new_turn(); - un.new_scenario(); + for (unit_map::iterator it = units_.begin(); it != units_.end(); it++) { + UnitPtr un = it.get_shared_ptr(); + if (teams_[un->side() - 1].persistent()) { + un->new_turn(); + un->new_scenario(); #if 0 - teams_[un.side() - 1].recall_list().push_back(un); + teams_[un->side() - 1].recall_list().push_back(un); #endif } } @@ -140,14 +141,14 @@ void game_board::side_change_controller(int side_num, team::CONTROLLER ctrl, con } } -bool game_board::try_add_unit_to_recall_list(const map_location& loc, const unit& u) +bool game_board::try_add_unit_to_recall_list(const map_location& loc, const UnitPtr u) { - if(teams_[u.side()-1].persistent()) { - teams_[u.side()-1].recall_list().push_back(u); + if(teams_[u->side()-1].persistent()) { + teams_[u->side()-1].recall_list().push_back(u); return true; } else { - ERR_RG << "unit with id " << u.id() << ": location (" << loc.x << "," << loc.y <<") is not on the map, and player " - << u.side() << " has no recall list.\n"; + ERR_RG << "unit with id " << u->id() << ": location (" << loc.x << "," << loc.y <<") is not on the map, and player " + << u->side() << " has no recall list.\n"; return false; } } @@ -167,7 +168,7 @@ boost::optional game_board::replace_map(const gamemap & newmap) { for (unit_map::iterator itor = units_.begin(); itor != units_.end(); ) { if (!newmap.on_board(itor->get_location())) { - if (!try_add_unit_to_recall_list(itor->get_location(), *itor)) { + if (!try_add_unit_to_recall_list(itor->get_location(), itor.get_shared_ptr())) { *ret = std::string("replace_map: Cannot add a unit that would become off-map to the recall list\n"); } units_.erase(itor++); @@ -256,9 +257,9 @@ void game_board::write_config(config & cfg) const { } //recall list { - BOOST_FOREACH(const unit & j, t->recall_list()) { + BOOST_FOREACH(const UnitConstPtr & j, t->recall_list()) { config& u = side.add_child("unit"); - j.write(u); + j->write(u); } } } @@ -322,7 +323,7 @@ temporary_unit_remover::~temporary_unit_remover() temporary_unit_mover::temporary_unit_mover(unit_map& m, const map_location& src, const map_location& dst, int new_moves) : m_(m), src_(src), dst_(dst), old_moves_(-1), - temp_(src == dst ? NULL : m_.extract(dst)) + temp_(src == dst ? UnitPtr() : m_.extract(dst)) { std::pair move_result = m_.move(src_, dst_); @@ -337,7 +338,7 @@ temporary_unit_mover::temporary_unit_mover(unit_map& m, const map_location& src, temporary_unit_mover::temporary_unit_mover(game_board& b, const map_location& src, const map_location& dst, int new_moves) : m_(b.units_), src_(src), dst_(dst), old_moves_(-1), - temp_(src == dst ? NULL : m_.extract(dst)) + temp_(src == dst ? UnitPtr() : m_.extract(dst)) { std::pair move_result = m_.move(src_, dst_); @@ -356,7 +357,7 @@ temporary_unit_mover::temporary_unit_mover(game_board& b, const map_location& sr temporary_unit_mover::temporary_unit_mover(unit_map& m, const map_location& src, const map_location& dst) : m_(m), src_(src), dst_(dst), old_moves_(-1), - temp_(src == dst ? NULL : m_.extract(dst)) + temp_(src == dst ? UnitPtr() : m_.extract(dst)) { m_.move(src_, dst_); } @@ -364,7 +365,7 @@ temporary_unit_mover::temporary_unit_mover(unit_map& m, const map_location& src, temporary_unit_mover::temporary_unit_mover(game_board& b, const map_location& src, const map_location& dst) : m_(b.units_), src_(src), dst_(dst), old_moves_(-1), - temp_(src == dst ? NULL : m_.extract(dst)) + temp_(src == dst ? UnitPtr() : m_.extract(dst)) { m_.move(src_, dst_); } diff --git a/src/game_board.hpp b/src/game_board.hpp index 8c11c77d0150..db84bd3b5437 100644 --- a/src/game_board.hpp +++ b/src/game_board.hpp @@ -23,6 +23,7 @@ #include #include +#include #include class config; @@ -115,7 +116,7 @@ class game_board : public display_context { // Manipulator from actionwml - bool try_add_unit_to_recall_list(const map_location& loc, const unit& u); + bool try_add_unit_to_recall_list(const map_location& loc, const UnitPtr u); boost::optional replace_map (const gamemap & r); void overlay_map (const gamemap & o, const config & cfg, map_location loc, bool border); @@ -153,7 +154,7 @@ struct temporary_unit_placer private: unit_map& m_; const map_location loc_; - unit *temp_; + UnitPtr temp_; }; // Begin Temporary Unit Move Structs @@ -174,7 +175,7 @@ struct temporary_unit_remover private: unit_map& m_; const map_location loc_; - unit *temp_; + UnitPtr temp_; }; @@ -200,7 +201,7 @@ struct temporary_unit_mover const map_location src_; const map_location dst_; int old_moves_; - unit *temp_; + UnitPtr temp_; }; diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index 52080761f077..995b691083a2 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -970,10 +970,10 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) for(std::vector::iterator pi = resources::teams->begin(); pi!=resources::teams->end(); ++pi) { - std::vector& avail_units = pi->recall_list(); - for(std::vector::iterator j = avail_units.begin(); j != avail_units.end();) { + std::vector& avail_units = pi->recall_list(); + for(std::vector::iterator j = avail_units.begin(); j != avail_units.end();) { scoped_recall_unit auto_store("this_unit", pi->save_id(), j - avail_units.begin()); - if (j->matches_filter(cfg, map_location())) { + if ((*j)->matches_filter(cfg, map_location())) { j = avail_units.erase(j); } else { ++j; @@ -1574,16 +1574,16 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) continue; } - std::vector& avail = (*resources::teams)[index].recall_list(); + std::vector& avail = (*resources::teams)[index].recall_list(); std::vector leaders = resources::units->find_leaders(index + 1); - for(std::vector::iterator u = avail.begin(); u != avail.end(); ++u) { + for(std::vector::iterator u = avail.begin(); u != avail.end(); ++u) { DBG_NG << "checking unit against filter...\n"; scoped_recall_unit auto_store("this_unit", player_id, u - avail.begin()); - if (u->matches_filter(unit_filter, map_location())) { - DBG_NG << u->id() << " matched the filter...\n"; - const unit to_recruit(*u); - const unit* pass_check = &to_recruit; + if ((*u)->matches_filter(unit_filter, map_location())) { + DBG_NG << (*u)->id() << " matched the filter...\n"; + const UnitPtr to_recruit = *u; + const unit* pass_check = to_recruit.get(); if(!cfg["check_passability"].to_bool(true)) pass_check = NULL; const map_location cfg_loc = cfg_to_loc(cfg); @@ -1592,7 +1592,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) DBG_NG << "...considering " + leader->id() + " as the recalling leader...\n"; map_location loc = cfg_loc; if ( (leader_filter.null() || leader->matches_filter(leader_filter)) && - u->matches_filter(vconfig(leader->recall_filter()), map_location()) ) { + (*u)->matches_filter(vconfig(leader->recall_filter()), map_location()) ) { DBG_NG << "...matched the leader filter and is able to recall the unit.\n"; if(!resources::gameboard->map().on_board(loc)) loc = leader->get_location(); @@ -1601,7 +1601,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) if(resources::gameboard->map().on_board(loc)) { DBG_NG << "...valid location for the recall found. Recalling.\n"; avail.erase(u); // Erase before recruiting, since recruiting can fire more events - actions::place_recruit(to_recruit, loc, leader->get_location(), 0, true, + actions::place_recruit(*to_recruit, loc, leader->get_location(), 0, true, cfg["show"].to_bool(true), cfg["fire_event"].to_bool(false), true, true); return; @@ -1617,7 +1617,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) DBG_NG << "No usable leader found, but found usable location. Recalling.\n"; avail.erase(u); // Erase before recruiting, since recruiting can fire more events map_location null_location = map_location::null_location(); - actions::place_recruit(to_recruit, loc, null_location, 0, true, cfg["show"].to_bool(true), + actions::place_recruit(*to_recruit, loc, null_location, 0, true, cfg["show"].to_bool(true), cfg["fire_event"].to_bool(false), true, true); return; } @@ -1795,10 +1795,10 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) } // Iterate over the player's recall list to find a match for(size_t i=0; i < pi->recall_list().size(); ++i) { - unit& u = pi->recall_list()[i]; + UnitPtr & u = pi->recall_list()[i]; scoped_recall_unit auto_store("this_unit", player_id, i); - if (u.matches_filter(filter, map_location())) { - u.set_role(cfg["role"]); + if (u->matches_filter(filter, map_location())) { + u->set_role(cfg["role"]); found=true; break; } @@ -2513,16 +2513,16 @@ WML_HANDLER_FUNCTION(unstore_unit, /*event_info*/, cfg) try { config tmp_cfg(var); - const unit u(tmp_cfg, false); + const UnitPtr u = UnitPtr( new unit(tmp_cfg, false)); - preferences::encountered_units().insert(u.type_id()); + preferences::encountered_units().insert(u->type_id()); map_location loc = cfg_to_loc( (cfg.has_attribute("x") && cfg.has_attribute("y")) ? cfg : vconfig(var)); const bool advance = cfg["advance"].to_bool(true); if(resources::gameboard->map().on_board(loc)) { if (cfg["find_vacant"].to_bool()) { const unit* pass_check = NULL; - if (cfg["check_passability"].to_bool(true)) pass_check = &u; + if (cfg["check_passability"].to_bool(true)) pass_check = u.get(); loc = pathfind::find_vacant_tile( loc, pathfind::VACANT_ANY, @@ -2530,7 +2530,7 @@ WML_HANDLER_FUNCTION(unstore_unit, /*event_info*/, cfg) } resources::units->erase(loc); - resources::units->add(loc, u); + resources::units->add(loc, *u); std::string text = cfg["text"]; play_controller *controller = resources::controller; @@ -2547,19 +2547,19 @@ WML_HANDLER_FUNCTION(unstore_unit, /*event_info*/, cfg) && (loop_limit > 0) ) { loop_limit--; - int total_opt = unit_helper::number_of_possible_advances(u); - bool use_dialog = side == u.side() && + int total_opt = unit_helper::number_of_possible_advances(*u); + bool use_dialog = side == u->side() && (*resources::teams)[side - 1].is_human(); config selected = mp_sync::get_user_choice("choose", unstore_unit_advance_choice(total_opt, loc, use_dialog)); dialogs::animate_unit_advancement(loc, selected["value"], cfg["fire_event"].to_bool(false), cfg["animate"].to_bool(true)); } } else { - if(advance && u.advances()) { + if(advance && u->advances()) { WRN_NG << "Cannot advance units when unstoring to the recall list." << std::endl; } - team& t = (*resources::teams)[u.side()-1]; + team& t = (*resources::teams)[u->side()-1]; if(t.persistent()) { @@ -2570,12 +2570,12 @@ WML_HANDLER_FUNCTION(unstore_unit, /*event_info*/, cfg) // replaced by the wrong unit. if(t.recall_list().size() > 1) { std::vector desciptions; - for(std::vector::const_iterator citor = + for(std::vector::const_iterator citor = t.recall_list().begin(); citor != t.recall_list().end(); ++citor) { const size_t desciption = - citor->underlying_id(); + (*citor)->underlying_id(); if(std::find(desciptions.begin(), desciptions.end(), desciption) != desciptions.end()) { @@ -2593,29 +2593,29 @@ WML_HANDLER_FUNCTION(unstore_unit, /*event_info*/, cfg) * @todo it would be better to change recall_list() from * a vector to a map and use the underlying_id as key. */ - const size_t key = u.underlying_id(); - for(std::vector::iterator itor = + const size_t key = u->underlying_id(); + for(std::vector::iterator itor = t.recall_list().begin(); itor != t.recall_list().end(); ++itor) { LOG_NG << "Replaced unit '" << key << "' on the recall list\n"; - if(itor->underlying_id() == key) { + if((*itor)->underlying_id() == key) { t.recall_list().erase(itor); break; } } t.recall_list().push_back(u); } else { - ERR_NG << "Cannot unstore unit: recall list is empty for player " << u.side() + ERR_NG << "Cannot unstore unit: recall list is empty for player " << u->side() << " and the map location is invalid.\n"; } } // If we unstore a leader make sure the team gets a leader if not the loading // in MP might abort since a side without a leader has a recall list. - if(u.can_recruit()) { - (*resources::teams)[u.side() - 1].have_leader(); + if(u->can_recruit()) { + (*resources::teams)[u->side() - 1].have_leader(); } } catch (game::game_error &e) { diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index 2eaa4000d184..19839701f770 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -89,13 +89,13 @@ namespace { // Support functions if(counts == default_counts && match_count) { break; } - const std::vector& avail_units = team->recall_list(); - for(std::vector::const_iterator unit = avail_units.begin(); unit!=avail_units.end(); ++unit) { + const std::vector& avail_units = team->recall_list(); + for(std::vector::const_iterator unit = avail_units.begin(); unit!=avail_units.end(); ++unit) { if(counts == default_counts && match_count) { break; } scoped_recall_unit auto_store("this_unit", team->save_id(), unit - avail_units.begin()); - if ( unit->matches_filter(*u) ) { + if ( (*unit)->matches_filter(*u) ) { ++match_count; } } diff --git a/src/game_preferences.cpp b/src/game_preferences.cpp index a5df387f484c..8e76c322e48b 100644 --- a/src/game_preferences.cpp +++ b/src/game_preferences.cpp @@ -1061,8 +1061,8 @@ void encounter_start_units(const unit_map& units){ static void encounter_recallable_units(const std::vector& teams){ BOOST_FOREACH(const team& t, teams) { - BOOST_FOREACH(const unit& u, t.recall_list()) { - encountered_units_set.insert(u.type_id()); + BOOST_FOREACH(const UnitConstPtr & u, t.recall_list()) { + encountered_units_set.insert(u->type_id()); } } } diff --git a/src/gamestatus.cpp b/src/gamestatus.cpp index a216c04c1f6f..fa223e86643b 100644 --- a/src/gamestatus.cpp +++ b/src/gamestatus.cpp @@ -253,8 +253,7 @@ class team_builder { //seen before config u_tmp = u; u_tmp["side"] = str_cast(side_); - unit new_unit(u_tmp, true); - t_->recall_list().push_back(new_unit); + t_->recall_list().push_back(UnitPtr(new unit(u_tmp,true))); } else { //not seen before unit_configs_.push_back(&u); diff --git a/src/gui/dialogs/gamestate_inspector.cpp b/src/gui/dialogs/gamestate_inspector.cpp index 2834af1e6eef..5fa4961221a5 100644 --- a/src/gui/dialogs/gamestate_inspector.cpp +++ b/src/gui/dialogs/gamestate_inspector.cpp @@ -414,19 +414,19 @@ class team_mode_controller : public single_mode_controller } if(selected == 3) { - const std::vector recall_list + const std::vector recall_list = resources::teams ? resources::teams->at(side_ - 1).recall_list() - : std::vector(); + : std::vector(); std::stringstream s; FOREACH(const AUTO & u, recall_list) { - s << "id=\"" << u.id() << "\" (" << u.type_id() << ")\nL" - << u.level() << "; " << u.experience() << "/" - << u.max_experience() << " xp; " << u.hitpoints() << "/" - << u.max_hitpoints() << " hp\n"; - FOREACH(const AUTO & str, u.get_traits_list()) + s << "id=\"" << u->id() << "\" (" << u->type_id() << ")\nL" + << u->level() << "; " << u->experience() << "/" + << u->max_experience() << " xp; " << u->hitpoints() << "/" + << u->max_hitpoints() << " hp\n"; + FOREACH(const AUTO & str, u->get_traits_list()) { s << "\t" << str << std::endl; } @@ -437,16 +437,16 @@ class team_mode_controller : public single_mode_controller } if(selected == 4) { - const std::vector recall_list + const std::vector recall_list = resources::teams ? resources::teams->at(side_ - 1).recall_list() - : std::vector(); + : std::vector(); config c; FOREACH(const AUTO & u, recall_list) { config c_unit; - u.write(c_unit); + u->write(c_unit); c.add_child("unit", c_unit); } model_.set_inspect_window_text(config_to_string(c)); diff --git a/src/menu_events.cpp b/src/menu_events.cpp index 6999810eb8e5..f93a0bdeed05 100644 --- a/src/menu_events.cpp +++ b/src/menu_events.cpp @@ -667,7 +667,7 @@ void menu_handler::recall(int side_num, const map_location &last_hex) return; } - std::vector recall_list_team; + std::vector recall_list_team; { wb::future_map future; // ensures recall list has planned recalls removed recall_list_team = actions::get_recalls(side_num, last_hex); } @@ -676,7 +676,7 @@ void menu_handler::recall(int side_num, const map_location &last_hex) DBG_WB <<"menu_handler::recall: Contents of wb-modified recall list:\n"; - BOOST_FOREACH(const unit* unit, recall_list_team) + BOOST_FOREACH(const UnitConstPtr & unit, recall_list_team) { DBG_WB << unit->name() << " [" << unit->id() <<"]\n"; } diff --git a/src/mouse_events.cpp b/src/mouse_events.cpp index bb3f82b94cbd..614e73eed4c1 100644 --- a/src/mouse_events.cpp +++ b/src/mouse_events.cpp @@ -1033,8 +1033,8 @@ int mouse_handler::show_attack_dialog(const map_location& attacker_loc, const ma } } if (items.empty()) { - dialogs::units_list_preview_pane attacker_preview(&*attacker, dialogs::unit_preview_pane::SHOW_BASIC, true); - dialogs::units_list_preview_pane defender_preview(&*defender, dialogs::unit_preview_pane::SHOW_BASIC, false); + dialogs::units_list_preview_pane attacker_preview(attacker.get_shared_ptr(), dialogs::unit_preview_pane::SHOW_BASIC, true); + dialogs::units_list_preview_pane defender_preview(defender.get_shared_ptr(), dialogs::unit_preview_pane::SHOW_BASIC, false); std::vector preview_panes; preview_panes.push_back(&attacker_preview); preview_panes.push_back(&defender_preview); @@ -1051,8 +1051,8 @@ int mouse_handler::show_attack_dialog(const map_location& attacker_loc, const ma std::vector buttons; buttons.push_back(gui::dialog_button_info(&ap_displayer, _("Damage Calculations"))); - dialogs::units_list_preview_pane attacker_preview(&*attacker, dialogs::unit_preview_pane::SHOW_BASIC, true); - dialogs::units_list_preview_pane defender_preview(&*defender, dialogs::unit_preview_pane::SHOW_BASIC, false); + dialogs::units_list_preview_pane attacker_preview(attacker.get_shared_ptr(), dialogs::unit_preview_pane::SHOW_BASIC, true); + dialogs::units_list_preview_pane defender_preview(defender.get_shared_ptr(), dialogs::unit_preview_pane::SHOW_BASIC, false); std::vector preview_panes; preview_panes.push_back(&attacker_preview); preview_panes.push_back(&defender_preview); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 6e274b18a4c3..abe081cf42a8 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -513,8 +513,8 @@ static int impl_unit_collect(lua_State *L) */ static int impl_unit_equality(lua_State* L) { - unit* left = luaW_checkunit(L, 1); - unit* right = luaW_checkunit(L, 2); + UnitPtr left = luaW_checkunit(L, 1); + UnitPtr right = luaW_checkunit(L, 2); const bool equal = left->underlying_id() == right->underlying_id(); lua_pushboolean(L, equal); return 1; @@ -530,7 +530,7 @@ static int impl_unit_get(lua_State *L) { lua_unit *lu = static_cast(lua_touserdata(L, 1)); char const *m = luaL_checkstring(L, 2); - unit const *pu = lu->get(); + const UnitConstPtr pu = lu->get(); if (strcmp(m, "valid") == 0) { @@ -613,7 +613,7 @@ static int impl_unit_set(lua_State *L) { lua_unit *lu = static_cast(lua_touserdata(L, 1)); char const *m = luaL_checkstring(L, 2); - unit *pu = lu->get(); + UnitPtr pu = lu->get(); if (!pu) return luaL_argerror(L, 1, "unknown unit"); unit &u = *pu; @@ -653,7 +653,7 @@ static int impl_unit_status_get(lua_State *L) if (!lua_istable(L, 1)) return luaL_typerror(L, 1, "unit status"); lua_rawgeti(L, 1, 1); - unit const *u = luaW_tounit(L, -1); + const UnitConstPtr u = luaW_tounit(L, -1); if (!u) return luaL_argerror(L, 1, "unknown unit"); char const *m = luaL_checkstring(L, 2); lua_pushboolean(L, u->get_state(m)); @@ -671,7 +671,7 @@ static int impl_unit_status_set(lua_State *L) if (!lua_istable(L, 1)) return luaL_typerror(L, 1, "unit status"); lua_rawgeti(L, 1, 1); - unit *u = luaW_tounit(L, -1); + UnitPtr u = luaW_tounit(L, -1); if (!u) return luaL_argerror(L, 1, "unknown unit"); char const *m = luaL_checkstring(L, 2); u->set_state(m, luaW_toboolean(L, 3)); @@ -689,7 +689,7 @@ static int impl_unit_variables_get(lua_State *L) if (!lua_istable(L, 1)) return luaL_typerror(L, 1, "unit variables"); lua_rawgeti(L, 1, 1); - unit const *u = luaW_tounit(L, -1); + const UnitConstPtr u = luaW_tounit(L, -1); if (!u) return luaL_argerror(L, 1, "unknown unit"); char const *m = luaL_checkstring(L, 2); return_cfgref_attrib("__cfg", u->variables()); @@ -708,7 +708,7 @@ static int impl_unit_variables_set(lua_State *L) if (!lua_istable(L, 1)) return luaL_typerror(L, 1, "unit variables"); lua_rawgeti(L, 1, 1); - unit *u = luaW_tounit(L, -1); + UnitPtr u = luaW_tounit(L, -1); if (!u) return luaL_argerror(L, 1, "unknown unit"); char const *m = luaL_checkstring(L, 2); if (strcmp(m, "__cfg") == 0) { @@ -838,7 +838,7 @@ static int intf_match_unit(lua_State *L) return luaL_typerror(L, 1, "unit"); lua_unit *lu = static_cast(lua_touserdata(L, 1)); - unit *u = lu->get(); + UnitPtr u = lu->get(); if (!u) return luaL_argerror(L, 1, "unit not found"); vconfig filter = luaW_checkvconfig(L, 2, true); @@ -850,8 +850,9 @@ static int intf_match_unit(lua_State *L) if (int side = lu->on_recall_list()) { team &t = (*resources::teams)[side - 1]; + std::vector::iterator it = find_if_matches_id(t.recall_list(), u->id()); scoped_recall_unit auto_store("this_unit", - t.save_id(), u - &t.recall_list()[0]); + t.save_id(), it - t.recall_list().begin()); lua_pushboolean(L, u->matches_filter(filter, map_location())); return 1; } @@ -880,15 +881,16 @@ static int intf_get_recall_units(lua_State *L) int i = 1, s = 1; BOOST_FOREACH(team &t, *resources::teams) { - BOOST_FOREACH(unit &u, t.recall_list()) + BOOST_FOREACH(UnitPtr & u, t.recall_list()) { if (!filter.null()) { + std::vector::iterator it = find_if_matches_id(t.recall_list(), u->id()); scoped_recall_unit auto_store("this_unit", - t.save_id(), &u - &t.recall_list()[0]); - if (!u.matches_filter(filter, map_location())) + t.save_id(), it - t.recall_list().begin()); + if (!u->matches_filter(filter, map_location())) continue; } - new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u.underlying_id()); + new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id()); lua_pushvalue(L, 1); lua_setmetatable(L, 3); lua_rawseti(L, 2, i); @@ -1749,7 +1751,7 @@ static int intf_find_path(lua_State *L) int arg = 1; map_location src, dst; unit_map &units = *resources::units; - const unit *u = NULL; + UnitConstPtr u = UnitConstPtr(); if (lua_isuserdata(L, arg)) { @@ -1763,7 +1765,7 @@ static int intf_find_path(lua_State *L) ++arg; src.y = luaL_checkinteger(L, arg) - 1; unit_map::const_unit_iterator ui = units.find(src); - if (ui.valid()) u = &*ui; + if (ui.valid()) u = ui.get_shared_ptr(); ++arg; } @@ -1859,7 +1861,7 @@ static int intf_find_path(lua_State *L) static int intf_find_reach(lua_State *L) { int arg = 1; - const unit *u = NULL; + UnitConstPtr u = UnitConstPtr(); if (lua_isuserdata(L, arg)) { @@ -1875,7 +1877,7 @@ static int intf_find_reach(lua_State *L) unit_map::const_unit_iterator ui = resources::units->find(src); if (!ui.valid()) return luaL_argerror(L, 1, "unit not found"); - u = &*ui; + u = ui.get_shared_ptr(); ++arg; } @@ -1944,7 +1946,7 @@ static int intf_find_reach(lua_State *L) static int intf_find_cost_map(lua_State *L) { int arg = 1; - const unit *u = luaW_tounit(L, arg, true); + UnitConstPtr u = luaW_tounit(L, arg, true); vconfig filter = vconfig::unconstructed_vconfig(); luaW_tovconfig(L, arg, filter); @@ -1955,7 +1957,7 @@ static int intf_find_cost_map(lua_State *L) if (u) // 1. arg - unit { - real_units.push_back(u); + real_units.push_back(u.get()); } else if (!filter.null()) // 1. arg - filter { @@ -2147,7 +2149,7 @@ static int intf_put_unit(lua_State *L) int unit_arg = 1; lua_unit *lu = NULL; - unit *u = NULL; + UnitPtr u = UnitPtr(); map_location loc; if (lua_isnumber(L, 1)) { unit_arg = 3; @@ -2180,7 +2182,7 @@ static int intf_put_unit(lua_State *L) if (!resources::gameboard->map().on_board(loc)) return luaL_argerror(L, 1, "invalid location"); } - u = new unit(cfg, true); + u = UnitPtr (new unit(cfg, true)); } resources::screen->invalidate(loc); @@ -2206,7 +2208,7 @@ static int intf_put_unit(lua_State *L) static int intf_put_recall_unit(lua_State *L) { lua_unit *lu = NULL; - unit *u = NULL; + UnitPtr u = UnitPtr(); int side = lua_tointeger(L, 2); if (unsigned(side) > resources::teams->size()) side = 0; @@ -2220,25 +2222,25 @@ static int intf_put_recall_unit(lua_State *L) else { config cfg = luaW_checkconfig(L, 1); - u = new unit(cfg, true); + u = UnitPtr(new unit(cfg, true)); } if (!side) side = u->side(); team &t = (*resources::teams)[side - 1]; if (!t.persistent()) return luaL_argerror(L, 2, "nonpersistent side"); - std::vector &rl = t.recall_list(); + std::vector &rl = t.recall_list(); // Avoid duplicates in the recall list. size_t uid = u->underlying_id(); - std::vector::iterator i = rl.begin(); + std::vector::iterator i = rl.begin(); while (i != rl.end()) { - if (i->underlying_id() == u->underlying_id()) { + if ((*i)->underlying_id() == u->underlying_id()) { i = rl.erase(i); } else ++i; } - rl.push_back(*u); + rl.push_back(u); if (lu) { if (lu->on_map()) resources::units->erase(u->get_location()); @@ -2258,7 +2260,7 @@ static int intf_extract_unit(lua_State *L) if (!luaW_hasmetatable(L, 1, getunitKey)) return luaL_typerror(L, 1, "unit"); lua_unit *lu = static_cast(lua_touserdata(L, 1)); - unit *u = lu->get(); + UnitPtr u = lu->get(); if (!u) return luaL_argerror(L, 1, "unit not found"); if (lu->on_map()) { @@ -2267,9 +2269,10 @@ static int intf_extract_unit(lua_State *L) u->clear_haloes(); } else if (int side = lu->on_recall_list()) { team &t = (*resources::teams)[side - 1]; - unit *v = new unit(*u); - std::vector &rl = t.recall_list(); - rl.erase(rl.begin() + (u - &rl[0])); + UnitPtr v = UnitPtr(new unit(*u)); + std::vector &rl = t.recall_list(); + std::vector::iterator it = find_if_matches_id(t.recall_list(), u->id()); + rl.erase(rl.begin() + (it - rl.begin())); u = v; } else { return 0; @@ -2290,22 +2293,18 @@ static int intf_find_vacant_tile(lua_State *L) { int x = luaL_checkint(L, 1) - 1, y = luaL_checkint(L, 2) - 1; - const unit *u = NULL; - bool fake_unit = false; + UnitPtr u = UnitPtr(); if (!lua_isnoneornil(L, 3)) { if (luaW_hasmetatable(L, 3, getunitKey)) { u = static_cast(lua_touserdata(L, 3))->get(); } else { config cfg = luaW_checkconfig(L, 3); - u = new unit(cfg, false); - fake_unit = true; + u.reset(new unit(cfg, false)); } } map_location res = find_vacant_tile(map_location(x, y), - pathfind::VACANT_ANY, u); - - if (fake_unit) delete u; + pathfind::VACANT_ANY, u.get()); if (!res.valid()) return 0; lua_pushinteger(L, res.x + 1); @@ -2338,7 +2337,7 @@ static int intf_float_label(lua_State *L) static int intf_create_unit(lua_State *L) { config cfg = luaW_checkconfig(L, 1); - unit *u = new unit(cfg, true); + UnitPtr u = UnitPtr(new unit(cfg, true)); new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(u); lua_pushlightuserdata(L , getunitKey); @@ -2354,8 +2353,8 @@ static int intf_create_unit(lua_State *L) */ static int intf_copy_unit(lua_State *L) { - unit const *u = luaW_checkunit(L, 1); - new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(new unit(*u)); + UnitPtr u = luaW_checkunit(L, 1); + new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(UnitPtr(new unit(*u))); lua_pushlightuserdata(L , getunitKey); lua_rawget(L, LUA_REGISTRYINDEX); @@ -2373,7 +2372,7 @@ static int intf_copy_unit(lua_State *L) */ static int intf_unit_resistance(lua_State *L) { - unit const *u = luaW_checkunit(L, 1); + const UnitConstPtr u = luaW_checkunit(L, 1); char const *m = luaL_checkstring(L, 2); bool a = luaW_toboolean(L, 3); @@ -2395,7 +2394,7 @@ static int intf_unit_resistance(lua_State *L) */ static int intf_unit_movement_cost(lua_State *L) { - unit const *u = luaW_checkunit(L, 1); + const UnitConstPtr u = luaW_checkunit(L, 1); char const *m = luaL_checkstring(L, 2); t_translation::t_terrain t = t_translation::read_terrain_code(m); lua_pushinteger(L, u->movement_cost(t)); @@ -2410,7 +2409,7 @@ static int intf_unit_movement_cost(lua_State *L) */ static int intf_unit_defense(lua_State *L) { - unit const *u = luaW_checkunit(L, 1); + const UnitConstPtr u = luaW_checkunit(L, 1); char const *m = luaL_checkstring(L, 2); t_translation::t_terrain t = t_translation::read_terrain_code(m); lua_pushinteger(L, u->defense_modifier(t)); @@ -2425,7 +2424,7 @@ static int intf_unit_defense(lua_State *L) */ static int intf_unit_ability(lua_State *L) { - unit const *u = luaW_checkunit(L, 1); + const UnitConstPtr u = luaW_checkunit(L, 1); char const *m = luaL_checkstring(L, 2); lua_pushboolean(L, u->get_ability_bool(m)); return 1; @@ -2438,7 +2437,7 @@ static int intf_unit_ability(lua_State *L) */ static int intf_transform_unit(lua_State *L) { - unit *u = luaW_checkunit(L, 1); + UnitPtr u = luaW_checkunit(L, 1); char const *m = luaL_checkstring(L, 2); const unit_type *utp = unit_types.find(m); if (!utp) return luaL_argerror(L, 2, "unknown unit type"); @@ -2533,7 +2532,7 @@ static int intf_simulate_combat(lua_State *L) { int arg_num = 1, att_w = -1, def_w = -1; - unit const *att = luaW_checkunit(L, arg_num); + UnitConstPtr att = luaW_checkunit(L, arg_num); ++arg_num; if (lua_isnumber(L, arg_num)) { att_w = lua_tointeger(L, arg_num) - 1; @@ -2542,7 +2541,7 @@ static int intf_simulate_combat(lua_State *L) ++arg_num; } - unit const *def = luaW_checkunit(L, arg_num, true); + UnitConstPtr def = luaW_checkunit(L, arg_num, true); ++arg_num; if (lua_isnumber(L, arg_num)) { def_w = lua_tointeger(L, arg_num) - 1; @@ -2552,7 +2551,7 @@ static int intf_simulate_combat(lua_State *L) } battle_context context(*resources::units, att->get_location(), - def->get_location(), att_w, def_w, 0.0, NULL, att); + def->get_location(), att_w, def_w, 0.0, NULL, att.get()); luaW_pushsimdata(L, context.get_attacker_combatant()); luaW_pushsimdata(L, context.get_defender_combatant()); @@ -3298,7 +3297,7 @@ static int intf_get_traits(lua_State* L) */ static int intf_add_modification(lua_State *L) { - unit *u = luaW_checkunit(L, 1); + UnitPtr u = luaW_checkunit(L, 1); char const *m = luaL_checkstring(L, 2); std::string sm = m; if (sm != "advance" && sm != "object" && sm != "trait") diff --git a/src/scripting/lua_api.cpp b/src/scripting/lua_api.cpp index d28ef79243ad..582cb038e044 100644 --- a/src/scripting/lua_api.cpp +++ b/src/scripting/lua_api.cpp @@ -386,21 +386,20 @@ bool luaW_getglobal(lua_State *L, ...) lua_unit::~lua_unit() { - delete ptr; } -unit *lua_unit::get() +UnitPtr lua_unit::get() { if (ptr) return ptr; if (side) { - BOOST_FOREACH(unit &u, (*resources::teams)[side - 1].recall_list()) { - if (u.underlying_id() == uid) return &u; + BOOST_FOREACH(UnitPtr &u, (*resources::teams)[side - 1].recall_list()) { + if (u->underlying_id() == uid) return u; } - return NULL; + return UnitPtr(); } unit_map::unit_iterator ui = resources::units->find(uid); - if (!ui.valid()) return NULL; - return &*ui; + if (!ui.valid()) return UnitPtr(); + return ui.get_shared_ptr(); //&*ui would not be legal, must get new shared_ptr by copy ctor because the unit_map itself is holding a boost shared pointer. } // Having this function here not only simplifies other code, it allows us to move @@ -414,24 +413,24 @@ bool lua_unit::put_map(const map_location &loc) resources::units->erase(loc); std::pair res = resources::units->insert(ptr); if (res.second) { - ptr = NULL; + ptr.reset(); uid = res.first->underlying_id(); } else { ERR_LUA << "Could not move unit " << ptr->underlying_id() << " onto map location " << loc << '\n'; return false; } } else if (side) { // recall list - std::vector &recall_list = (*resources::teams)[side - 1].recall_list(); - std::vector::iterator it = recall_list.begin(); + std::vector &recall_list = (*resources::teams)[side - 1].recall_list(); + std::vector::iterator it = recall_list.begin(); for(; it != recall_list.end(); ++it) { - if (it->underlying_id() == uid) { + if ((*it)->underlying_id() == uid) { break; } } if (it != recall_list.end()) { side = 0; // uid may be changed by unit_map on insertion - uid = resources::units->replace(loc, *it).first->underlying_id(); + uid = resources::units->replace(loc, **it).first->underlying_id(); recall_list.erase(it); } else { ERR_LUA << "Could not find unit " << uid << " on recall list of side " << side << '\n'; @@ -454,17 +453,17 @@ bool lua_unit::put_map(const map_location &loc) return true; } -unit *luaW_tounit(lua_State *L, int index, bool only_on_map) +UnitPtr luaW_tounit(lua_State *L, int index, bool only_on_map) { - if (!luaW_hasmetatable(L, index, getunitKey)) return NULL; + if (!luaW_hasmetatable(L, index, getunitKey)) return UnitPtr(); lua_unit *lu = static_cast(lua_touserdata(L, index)); - if (only_on_map && !lu->on_map()) return NULL; + if (only_on_map && !lu->on_map()) return UnitPtr(); return lu->get(); } -unit *luaW_checkunit(lua_State *L, int index, bool only_on_map) +UnitPtr luaW_checkunit(lua_State *L, int index, bool only_on_map) { - unit *u = luaW_tounit(L, index, only_on_map); + UnitPtr u = luaW_tounit(L, index, only_on_map); if (!u) luaL_typerror(L, index, "unit"); return u; } diff --git a/src/scripting/lua_api.hpp b/src/scripting/lua_api.hpp index ba979e0f9eb7..5c80aba3d277 100644 --- a/src/scripting/lua_api.hpp +++ b/src/scripting/lua_api.hpp @@ -19,16 +19,16 @@ #include #include "config.hpp" // forward declaration of the nested type config::attribute_value is not possible #include "lua_types.hpp" // the luatype typedef +#include "unit_ptr.hpp" + struct lua_State; class t_string; class vconfig; -class unit; - /** * Converts a Lua value to a unit pointer. */ -unit *luaW_tounit(lua_State *L, int index, bool only_on_map = false); +UnitPtr luaW_tounit(lua_State *L, int index, bool only_on_map = false); /** * Displays a message in the chat window. @@ -123,7 +123,7 @@ bool luaW_getglobal(lua_State *L, ...); /** * Converts a Lua value to a unit pointer. */ -unit *luaW_checkunit(lua_State *L, int index, bool only_on_map = false); +UnitPtr luaW_checkunit(lua_State *L, int index, bool only_on_map = false); bool luaW_toboolean(lua_State *L, int n); @@ -137,18 +137,18 @@ struct map_location; class lua_unit { size_t uid; - unit *ptr; + UnitPtr ptr; int side; lua_unit(lua_unit const &); public: - lua_unit(size_t u): uid(u), ptr(NULL), side(0) {} - lua_unit(unit *u): uid(0), ptr(u), side(0) {} - lua_unit(int s, size_t u): uid(u), ptr(NULL), side(s) {} + lua_unit(size_t u): uid(u), ptr(), side(0) {} + lua_unit(UnitPtr u): uid(0), ptr(u), side(0) {} + lua_unit(int s, size_t u): uid(u), ptr(), side(s) {} ~lua_unit(); bool on_map() const { return !ptr && side == 0; } int on_recall_list() const { return side; } - unit *get(); + UnitPtr get(); // Clobbers loc bool put_map(const map_location &loc); diff --git a/src/side_filter.cpp b/src/side_filter.cpp index 3c76847e5984..a968e8031fc9 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -137,10 +137,11 @@ bool side_filter::match_internal(const team &t) const } } if(!found && unit_filter["search_recall_list"].to_bool(false)) { - const std::vector& recall_list = t.recall_list(); - BOOST_FOREACH(const unit& u, recall_list) { - scoped_recall_unit this_unit("this_unit", t.save_id(), &u - &recall_list[0]); - if(u.matches_filter(unit_filter, u.get_location(), flat_)) { + const std::vector& recall_list = t.recall_list(); + BOOST_FOREACH(const UnitConstPtr & u, recall_list) { + std::vector::const_iterator it = find_if_matches_id(recall_list, u->id()); + scoped_recall_unit this_unit("this_unit", t.save_id(), it - recall_list.begin()); + if(u->matches_filter(unit_filter, u->get_location(), flat_)) { found = true; break; } diff --git a/src/synced_commands.cpp b/src/synced_commands.cpp index 56b7c8071aee..547f383f00ec 100644 --- a/src/synced_commands.cpp +++ b/src/synced_commands.cpp @@ -222,7 +222,7 @@ SYNCED_COMMAND_HANDLER_FUNCTION(disband, child, /*use_undo*/, /*show*/, error_ha team ¤t_team = (*resources::teams)[current_team_num - 1]; const std::string& unit_id = child["value"]; - std::vector::iterator disband_unit = + std::vector::iterator disband_unit = find_if_matches_id(current_team.recall_list(), unit_id); if(disband_unit != current_team.recall_list().end()) { diff --git a/src/team.hpp b/src/team.hpp index 6d6eef297d15..208bcef4c1b8 100644 --- a/src/team.hpp +++ b/src/team.hpp @@ -180,8 +180,8 @@ class team : public savegame::savegame_config { countdown_time_ = amount; } int action_bonus_count() const { return action_bonus_count_; } void set_action_bonus_count(const int count) { action_bonus_count_ = count; } - std::vector& recall_list() {return recall_list_;} - const std::vector& recall_list() const {return recall_list_;} + std::vector& recall_list() {return recall_list_;} + const std::vector& recall_list() const {return recall_list_;} void set_current_player(const std::string& player) { info_.current_player = player; } @@ -344,7 +344,7 @@ class team : public savegame::savegame_config mutable int countdown_time_; int action_bonus_count_; - std::vector recall_list_; + std::vector recall_list_; std::string last_recruit_; bool calculate_enemies(size_t index) const; diff --git a/src/tests/test_unit_map.cpp b/src/tests/test_unit_map.cpp index da9df959e0e1..e04f0e2a8e0e 100644 --- a/src/tests/test_unit_map.cpp +++ b/src/tests/test_unit_map.cpp @@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE( track_real_unit_by_underlying_id ) { BOOST_CHECK(ui->underlying_id() == orc1_side0_real.underlying_id()); } - unit* extracted_unit = unit_map.extract(hex); + UnitPtr extracted_unit = unit_map.extract(hex); { unit_map::unit_iterator ui = unit_map.find(underlying_id); @@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE( track_real_unit_by_underlying_id ) { } unit_map.insert(extracted_unit); - extracted_unit = NULL; + extracted_unit.reset(); { unit_map::unit_iterator ui = unit_map.find(underlying_id); @@ -198,7 +198,7 @@ BOOST_AUTO_TEST_CASE( track_fake_unit_by_underlying_id ) { BOOST_CHECK(ui->underlying_id() == orc1_side0_fake.underlying_id()); } - unit* extracted_unit = unit_map.extract(hex); + UnitPtr extracted_unit = unit_map.extract(hex); { unit_map::unit_iterator ui = unit_map.find(underlying_id); @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE( track_fake_unit_by_underlying_id ) { } unit_map.insert(extracted_unit); - extracted_unit = NULL; + extracted_unit.reset(); { unit_map::unit_iterator ui = unit_map.find(underlying_id); @@ -240,7 +240,7 @@ BOOST_AUTO_TEST_CASE( track_real_unit_by_iterator ) { BOOST_CHECK(unit_iterator.valid()); - unit* extracted_unit = unit_map.extract(hex); + UnitPtr extracted_unit = unit_map.extract(hex); BOOST_CHECK_MESSAGE(unit_iterator.valid() == false, "Iterator should be invalid after extraction."); @@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE( track_fake_unit_by_iterator ) { BOOST_CHECK(unit_iterator.valid()); - unit* extracted_unit = unit_map.extract(hex); + UnitPtr extracted_unit = unit_map.extract(hex); BOOST_CHECK_MESSAGE(unit_iterator.valid() == false, "Iterator should be invalid after extraction."); diff --git a/src/tests/test_whiteboard_side_actions.cpp b/src/tests/test_whiteboard_side_actions.cpp index 61a92290c99a..083420d3e0fe 100644 --- a/src/tests/test_whiteboard_side_actions.cpp +++ b/src/tests/test_whiteboard_side_actions.cpp @@ -37,7 +37,7 @@ struct dummy_action: action{ void remove_temp_modifier(unit_map&){} void draw_hex(const map_location&){} map_location get_numbering_hex() const { return map_location(); } - unit* get_unit() const { return 0; } + UnitPtr get_unit() const { return UnitPtr(); } fake_unit_ptr get_fake_unit(){ return fake_unit_ptr(); } error check_validity() const { return OK; } }; diff --git a/src/unit.cpp b/src/unit.cpp index 081015f947d6..a424ebce87d9 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -71,6 +71,22 @@ namespace { const std::string leader_crown_path = "misc/leader-crown.png"; } +/** + * Intrusive Pointer interface + * + **/ + +void intrusive_ptr_add_ref(const unit * u) +{ + ++(u->ref_count_); +} + +void intrusive_ptr_release(const unit * u) +{ + if (--(u->ref_count_) == 0) + delete u; +} + /** * Converts a string ID to a unit_type. * Throws a game_error exception if the string does not correspond to a type. @@ -2902,40 +2918,45 @@ bool unit::matches_id(const std::string& unit_id) const return id_ == unit_id; } +bool find_if_matches_helper(const UnitPtr & ptr, const std::string & unit_id) +{ + return ptr->matches_id(unit_id); +} + /** * Used to find units in vectors by their ID. (Convenience wrapper) * @returns what std::find_if() returns. */ -std::vector::iterator find_if_matches_id( - std::vector &unit_list, // Not const so we can get a non-const iterator to return. +std::vector::iterator find_if_matches_id( + std::vector &unit_list, // Not const so we can get a non-const iterator to return. const std::string &unit_id) { return std::find_if(unit_list.begin(), unit_list.end(), - boost::bind(&unit::matches_id, _1, unit_id)); + boost::bind(&find_if_matches_helper, _1, unit_id)); } /** * Used to find units in vectors by their ID. (Convenience wrapper; const version) * @returns what std::find_if() returns. */ -std::vector::const_iterator find_if_matches_id( - const std::vector &unit_list, +std::vector::const_iterator find_if_matches_id( + const std::vector &unit_list, const std::string &unit_id) { return std::find_if(unit_list.begin(), unit_list.end(), - boost::bind(&unit::matches_id, _1, unit_id)); + boost::bind(&find_if_matches_helper, _1, unit_id)); } /** * Used to erase units from vectors by their ID. (Convenience wrapper) * @returns what std::vector<>::erase() returns. */ -std::vector::iterator erase_if_matches_id( - std::vector &unit_list, +std::vector::iterator erase_if_matches_id( + std::vector &unit_list, const std::string &unit_id) { return unit_list.erase(std::remove_if(unit_list.begin(), unit_list.end(), - boost::bind(&unit::matches_id, _1, unit_id)), + boost::bind(&find_if_matches_helper, _1, unit_id)), unit_list.end()); } diff --git a/src/unit.hpp b/src/unit.hpp index b6a4d9165bf5..7af60646ab36 100644 --- a/src/unit.hpp +++ b/src/unit.hpp @@ -23,6 +23,7 @@ #include "unit_animation.hpp" #include "unit_types.hpp" #include "unit_map.hpp" +#include "unit_ptr.hpp" class display; class gamemap; @@ -391,7 +392,12 @@ class unit const std::string& effect_image_mods() const; std::string image_mods() const; + long ref_count() const { return ref_count_; } + friend void intrusive_ptr_add_ref(const unit *); + friend void intrusive_ptr_release(const unit *); private: + mutable long ref_count_; //used by intrusive_ptr + void advance_to(const config &old_cfg, const unit_type &t, bool use_traits); @@ -534,16 +540,16 @@ struct unit_movement_resetter }; /// Used to find units in vectors by their ID. (Convenience wrapper) -std::vector::iterator find_if_matches_id( - std::vector &unit_list, +std::vector::iterator find_if_matches_id( + std::vector &unit_list, const std::string &unit_id); /// Used to find units in vectors by their ID. (Convenience wrapper) -std::vector::const_iterator find_if_matches_id( - const std::vector &unit_list, +std::vector::const_iterator find_if_matches_id( + const std::vector &unit_list, const std::string &unit_id); /// Used to erase units from vectors by their ID. (Convenience wrapper) -std::vector::iterator erase_if_matches_id( - std::vector &unit_list, +std::vector::iterator erase_if_matches_id( + std::vector &unit_list, const std::string &unit_id); /** Returns the number of units of the side @a side_num. */ diff --git a/src/unit_map.cpp b/src/unit_map.cpp index 5fe8ce987456..92c128e4cb28 100644 --- a/src/unit_map.cpp +++ b/src/unit_map.cpp @@ -65,16 +65,16 @@ unit_map::~unit_map() { unit_map::t_umap::iterator unit_map::begin_core() const { self_check(); t_umap::iterator i = umap_.begin(); - while (i != umap_.end() && (i->second.unit == NULL)) { ++i; } + while (i != umap_.end() && (!i->second.unit)) { ++i; } return i; } std::pair unit_map::add(const map_location &l, const unit &u) { self_check(); - unit *p = new unit(u); + UnitPtr p = UnitPtr (new unit(u)); //TODO: should this instead take a shared pointer to a unit, rather than make a copy? p->set_location(l); std::pair res( insert(p) ); - if(res.second == false) { delete p; } + if(res.second == false) { p.reset(); } return res; } @@ -91,8 +91,8 @@ std::pair unit_map::move(const map_location &src, if(src == dst){ return std::make_pair(make_unit_iterator(uit), true);} //Fail if there is no unit to move - unit *p = uit->second.unit; - if(p == NULL){ return std::make_pair(make_unit_iterator(uit), false);} + UnitPtr p = uit->second.unit; + if(!p){ return std::make_pair(make_unit_iterator(uit), false);} p->set_location(dst); @@ -125,7 +125,7 @@ The one oddity is that to facilitate non-invalidating iterators the list sometimes has NULL pointers which should be used when they correspond to uids previously used. */ -std::pair unit_map::insert(unit *p) { +std::pair unit_map::insert(UnitPtr p) { self_check(); assert(p); @@ -139,7 +139,7 @@ std::pair unit_map::insert(unit *p) { } unit_pod upod; - upod.unit = p; + upod.unit = p ; DBG_NG << "Adding unit " << p->underlying_id() << " - " << p->id() << " to location: (" << loc << ")\n"; @@ -148,12 +148,12 @@ std::pair unit_map::insert(unit *p) { if (! uinsert.second) { //If the pod is empty reinsert the unit in the same list element - if ( uinsert.first->second.unit == NULL) { + if (!uinsert.first->second.unit) { unit_pod &opod = uinsert.first->second; - opod.unit = p; + opod.unit = p ; assert(opod.ref_count != 0); } else { - unit *q = uinsert.first->second.unit; + UnitPtr q = uinsert.first->second.unit; ERR_NG << "Trying to add " << p->name() << " - " << p->id() << " - " << p->underlying_id() << " (" << loc << ") over " << q->name() @@ -191,7 +191,7 @@ std::pair unit_map::insert(unit *p) { umap_.erase(uinsert.first); } else { //undo a reinsertion - uinsert.first->second.unit = NULL; + uinsert.first->second.unit.reset(); } DBG_NG << "Trying to add " << p->name() << " - " << p->id() << " at location ("<second.unit->underlying_id() << "\n"; - delete i->second.unit; + i->second.unit.reset(); } } @@ -246,14 +246,14 @@ void unit_map::clear(bool force) { umap_.clear(); } -unit *unit_map::extract(const map_location &loc) { +UnitPtr unit_map::extract(const map_location &loc) { self_check(); t_lmap::iterator i = lmap_.find(loc); - if (i == lmap_.end()) { return NULL; } + if (i == lmap_.end()) { return UnitPtr(); } t_umap::iterator uit(i->second); - unit *u = uit->second.unit; + UnitPtr u = uit->second.unit; size_t uid( u->underlying_id() ); DBG_NG << "Extract unit " << uid << " - " << u->id() @@ -264,7 +264,7 @@ unit *unit_map::extract(const map_location &loc) { umap_.erase(uit); } else { //Soft extraction keeps the old lit item if any iterators reference it - uit->second.unit = NULL; + uit->second.unit.reset(); } lmap_.erase(i); @@ -276,16 +276,16 @@ unit *unit_map::extract(const map_location &loc) { size_t unit_map::erase(const map_location &loc) { self_check(); - unit *u = extract(loc); + UnitPtr u = extract(loc); if (!u) return 0; - delete u; + u.reset(); return 1; } unit_map::unit_iterator unit_map::find(size_t id) { self_check(); t_umap::iterator i(umap_.find(id)); - if((i != umap_.end()) && i->second.unit==NULL){ i = umap_.end() ;} + if((i != umap_.end()) && !i->second.unit){ i = umap_.end() ;} return make_unit_iterator( i ); } @@ -343,14 +343,14 @@ bool unit_map::self_check() const { good=false; ERR_NG << "unit_map pod ref_count <0 is " << uit->second.ref_count<< std::endl; } - if(uit->second.unit != NULL){ + if(uit->second.unit){ uit->second.unit->id(); //crash if bad pointer } if(uit->first <= 0){ good=false; ERR_NG << "unit_map umap uid <=0 is " << uit->first << std::endl; } - if(uit->second.unit == NULL && uit->second.ref_count == 0 ){ + if(!uit->second.unit && uit->second.ref_count == 0 ){ good=false; ERR_NG << "unit_map umap unit==NULL when refcount == 0" << std::endl; } @@ -381,7 +381,7 @@ bool unit_map::has_unit(const unit * const u) const assert(u); BOOST_FOREACH(const t_umap::value_type& item, umap_) { - if(item.second.unit == u) { + if(item.second.unit.get() == u) { return true; } } diff --git a/src/unit_map.hpp b/src/unit_map.hpp index 0ab33789d10a..11a811b9e769 100644 --- a/src/unit_map.hpp +++ b/src/unit_map.hpp @@ -20,6 +20,7 @@ #include "utils/reference_counter.hpp" #include "map_location.hpp" +#include "unit_ptr.hpp" #include #include @@ -28,8 +29,6 @@ //#define DEBUG_UNIT_MAP -class unit; - /** * Container associating units to locations. * An indirection location -> underlying_id -> unit ensures that iterators @@ -94,12 +93,12 @@ class unit_map { struct unit_pod { unit_pod() - : unit(NULL) + : unit() , ref_count() { } - class unit * unit; + UnitPtr unit; mutable n_ref_counter::t_ref_counter ref_count; }; @@ -132,7 +131,7 @@ class unit_map { typedef std::forward_iterator_tag iterator_category; typedef int difference_type; typedef typename iter_types::value_type value_type; - typedef value_type* pointer; + typedef boost::intrusive_ptr pointer; typedef value_type& reference; typedef typename iter_types::container_type container_type; typedef typename iter_types::iterator_type iterator_type; @@ -178,6 +177,10 @@ class unit_map { assert(valid()); tank_->self_check(); return i_->second.unit; } + pointer get_shared_ptr() const { // This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax easily. + assert(valid()); + tank_->self_check(); + return i_->second.unit; } reference operator*() const { tank_->self_check(); assert(valid()); @@ -189,7 +192,7 @@ class unit_map { iterator_type new_i(i_); do{ ++new_i; - }while ((new_i != the_map().end()) && (new_i->second.unit == NULL)) ; + }while ((new_i != the_map().end()) && (!new_i->second.unit)) ; dec(); i_ = new_i; inc(); @@ -210,7 +213,7 @@ class unit_map { dec(); do { --i_ ; - }while(i_ != begin && (i_->second.unit == NULL)); + }while(i_ != begin && (!i_->second.unit)); inc(); valid_exit(); @@ -225,7 +228,7 @@ class unit_map { bool valid() const { if(valid_for_dereference()) { - return i_->second.unit != NULL; + return i_->second.unit; } return false; } @@ -254,7 +257,7 @@ class unit_map { void dec() { if( valid_ref_count() ){ assert(i_->second.ref_count != 0); - if( (--(i_->second.ref_count) == 0) && (i_->second.unit == NULL) ){ + if( (--(i_->second.ref_count) == 0) && (!i_->second.unit) ){ iterator_type old = i_++; tank_->umap_.erase(old); } @@ -334,7 +337,7 @@ class unit_map { * will be generated. * @note The map takes ownership of the pointed object, only if it succeeds. */ - std::pair insert(unit *p); + std::pair insert(UnitPtr p); /** * Moves a unit from location @a src to location @a dst. @@ -371,7 +374,7 @@ class unit_map { * The unit is no longer owned by the map. * It can be reinserted later, if needed. */ - unit *extract(const map_location &loc); + UnitPtr extract(const map_location &loc); ///Checks invariants. For debugging purposes only. Doesn't do anything in non-debug mode. bool self_check() const diff --git a/src/unit_ptr.hpp b/src/unit_ptr.hpp new file mode 100644 index 000000000000..af733ccdbd7c --- /dev/null +++ b/src/unit_ptr.hpp @@ -0,0 +1,32 @@ +/* + Copyright (C) 2014 by Chris Beck + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +// The purpose of this header is to forward declare the UnitPtr, if it +// is an intrusive pointer then this requires some boilerplate taken +// care of here. + +#ifndef UNIT_PTR_H_INCLUDED +#define UNIT_PTR_H_INCLUDED + +#include + +class unit; + +void intrusive_ptr_add_ref(const unit *); +void intrusive_ptr_release(const unit *); + +typedef boost::intrusive_ptr UnitPtr; +typedef boost::intrusive_ptr UnitConstPtr; + +#endif diff --git a/src/variable.cpp b/src/variable.cpp index 9dc1e57eac1d..c43c6554a707 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -428,7 +428,7 @@ void scoped_recall_unit::activate() if(team_it != teams.end()) { if(team_it->recall_list().size() > recall_index_) { config &tmp_cfg = store(); - team_it->recall_list()[recall_index_].write(tmp_cfg); + team_it->recall_list()[recall_index_]->write(tmp_cfg); tmp_cfg["x"] = "recall"; tmp_cfg["y"] = "recall"; LOG_NG << "auto-storing $" << name() << " for player: " << player_ diff --git a/src/whiteboard/action.cpp b/src/whiteboard/action.cpp index f04337c4e9cd..67d9266d9f46 100644 --- a/src/whiteboard/action.cpp +++ b/src/whiteboard/action.cpp @@ -116,7 +116,7 @@ action::~action() size_t action::get_unit_id() const { - unit *ret = get_unit(); + UnitPtr ret = get_unit(); return ret ? ret->underlying_id() : 0; } diff --git a/src/whiteboard/action.hpp b/src/whiteboard/action.hpp index f9e2dc13ef5e..4e40b8f2648d 100644 --- a/src/whiteboard/action.hpp +++ b/src/whiteboard/action.hpp @@ -66,7 +66,7 @@ class action : public boost::enable_shared_from_this virtual map_location get_numbering_hex() const = 0; /** Return the unit targeted by this action. Null if unit doesn't exist. */ - virtual unit* get_unit() const = 0; + virtual UnitPtr get_unit() const = 0; /** * Returns the id of the unit targeted by this action. diff --git a/src/whiteboard/highlighter.cpp b/src/whiteboard/highlighter.cpp index 5cac28a0129a..7964612928b5 100644 --- a/src/whiteboard/highlighter.cpp +++ b/src/whiteboard/highlighter.cpp @@ -48,8 +48,8 @@ highlighter::highlighter(unit_map& unit_map, side_actions_ptr side_actions) : unit_map_(unit_map) , mouseover_hex_() , exclusive_display_hexes_() - , owner_unit_(NULL) - , selection_candidate_(NULL) + , owner_unit_() + , selection_candidate_() , selected_action_() , main_highlight_() , secondary_highlights_() @@ -79,10 +79,10 @@ void highlighter::set_mouseover_hex(const map_location& hex) //if we're right over a unit, just highlight all of this unit's actions unit_map::iterator it = unit_map_.find(hex); if(it != unit_map_.end()) { - selection_candidate_ = &(*it); + selection_candidate_ = it.get_shared_ptr(); if(resources::teams->at(it->side()-1).get_side_actions()->unit_has_actions(*it)) { - owner_unit_ = &(*it); + owner_unit_ = it.get_shared_ptr(); } //commented code below is to also select the first action of this unit as @@ -121,7 +121,7 @@ void highlighter::clear() { unhighlight(); main_highlight_.reset(); - owner_unit_ = NULL; + owner_unit_.reset(); secondary_highlights_.clear(); selected_action_.reset(); } @@ -255,7 +255,7 @@ action_ptr highlighter::get_bump_target() return selected_action_.lock(); } -unit* highlighter::get_selection_target() +UnitPtr highlighter::get_selection_target() { if(owner_unit_) { return owner_unit_; diff --git a/src/whiteboard/highlighter.hpp b/src/whiteboard/highlighter.hpp index e8fe70493394..b786266d20c5 100644 --- a/src/whiteboard/highlighter.hpp +++ b/src/whiteboard/highlighter.hpp @@ -50,7 +50,7 @@ class highlighter action_ptr get_execute_target(); action_ptr get_delete_target(); action_ptr get_bump_target(); - unit* get_selection_target(); + UnitPtr get_selection_target(); /// @return the action that currently receives the highlight focus weak_action_ptr get_main_highlight() { return main_highlight_; } @@ -79,8 +79,8 @@ class highlighter map_location mouseover_hex_; std::set exclusive_display_hexes_; - unit* owner_unit_; - unit* selection_candidate_; + UnitPtr owner_unit_; + UnitPtr selection_candidate_; weak_action_ptr selected_action_; weak_action_ptr main_highlight_; diff --git a/src/whiteboard/manager.cpp b/src/whiteboard/manager.cpp index 07c19d31e3f2..cedd0c6eed55 100644 --- a/src/whiteboard/manager.cpp +++ b/src/whiteboard/manager.cpp @@ -326,8 +326,8 @@ void manager::post_delete_action(action_ptr action) side_actions_ptr side_actions = resources::teams->at(action->team_index()).get_side_actions(); - unit *actor = action->get_unit(); - if(actor != NULL) { // The unit might have died following the execution of an attack + UnitPtr actor = action->get_unit(); + if(actor) { // The unit might have died following the execution of an attack side_actions::iterator action_it = side_actions->find_last_action_of(*actor); if(action_it != side_actions->end()) { move_ptr move = boost::dynamic_pointer_cast(*action_it); diff --git a/src/whiteboard/mapbuilder.cpp b/src/whiteboard/mapbuilder.cpp index e85f9e7ec027..b4d54e84b498 100644 --- a/src/whiteboard/mapbuilder.cpp +++ b/src/whiteboard/mapbuilder.cpp @@ -117,12 +117,12 @@ void mapbuilder::process(side_actions &sa, side_actions::iterator action_it) { action_ptr action = *action_it; bool acted=false; - unit* unit = action->get_unit(); + UnitPtr unit = action->get_unit(); if(!unit) { return; } - if(acted_this_turn_.find(unit) == acted_this_turn_.end()) { + if(acted_this_turn_.find(unit.get()) == acted_this_turn_.end()) { //reset MP unit->set_movement(unit->total_movement()); acted=true; @@ -134,9 +134,9 @@ void mapbuilder::process(side_actions &sa, side_actions::iterator action_it) if(erval != action::OK) { // We do not delete obstructed moves, nor invalid actions caused by obstructed moves. - if(has_invalid_actions_.find(unit) == has_invalid_actions_.end()) { + if(has_invalid_actions_.find(unit.get()) == has_invalid_actions_.end()) { if(erval == action::TOO_FAR || (erval == action::LOCATION_OCCUPIED && boost::dynamic_pointer_cast(action))) { - has_invalid_actions_.insert(unit); + has_invalid_actions_.insert(unit.get()); invalid_actions_.push_back(action_it); } else { sa.remove_action(action_it, false); @@ -149,10 +149,10 @@ void mapbuilder::process(side_actions &sa, side_actions::iterator action_it) } // We do not keep invalid actions replaced by a valid one. - std::set::iterator invalid_it = has_invalid_actions_.find(unit); + std::set::iterator invalid_it = has_invalid_actions_.find(unit.get()); if(invalid_it != has_invalid_actions_.end()) { for(std::list::iterator it = invalid_actions_.begin(); it != invalid_actions_.end();) { - if((**it)->get_unit() == unit) { + if((**it)->get_unit().get() == unit.get()) { sa.remove_action(*it, false); it = invalid_actions_.erase(it); } else { @@ -163,7 +163,7 @@ void mapbuilder::process(side_actions &sa, side_actions::iterator action_it) } if(acted) { - acted_this_turn_.insert(unit); + acted_this_turn_.insert(unit.get()); } action->apply_temp_modifier(unit_map_); @@ -181,8 +181,8 @@ void mapbuilder::post_visit_team(size_t turn) move_ptr move = boost::dynamic_pointer_cast(action); if(move) { move->set_turn_number(0); - if(move->get_route().steps.size() > 1 && seen.count(move->get_unit()) == 0) { - seen.insert(move->get_unit()); + if(move->get_route().steps.size() > 1 && seen.count(move->get_unit().get()) == 0) { + seen.insert(move->get_unit().get()); move->set_turn_number(turn + 1); } } diff --git a/src/whiteboard/move.cpp b/src/whiteboard/move.cpp index 2fe9707a3cfd..3622e6b7f558 100644 --- a/src/whiteboard/move.cpp +++ b/src/whiteboard/move.cpp @@ -275,13 +275,13 @@ void move::execute(bool& success, bool& complete) } } -unit* move::get_unit() const +UnitPtr move::get_unit() const { unit_map::iterator itor = resources::units->find(unit_underlying_id_); if (itor.valid()) - return &*itor; + return itor.get_shared_ptr(); else - return NULL; + return UnitPtr(); } map_location move::get_source_hex() const diff --git a/src/whiteboard/move.hpp b/src/whiteboard/move.hpp index bbc7759fb012..248f969cbe94 100644 --- a/src/whiteboard/move.hpp +++ b/src/whiteboard/move.hpp @@ -52,7 +52,7 @@ class move : public action virtual error check_validity() const; /** Return the unit targeted by this action. Null if unit doesn't exist. */ - virtual unit* get_unit() const; + virtual UnitPtr get_unit() const; /** @return pointer to the fake unit used only for visuals */ virtual fake_unit_ptr get_fake_unit() { return fake_unit_; } diff --git a/src/whiteboard/recall.cpp b/src/whiteboard/recall.cpp index 10d77f37d127..f937058aef2c 100644 --- a/src/whiteboard/recall.cpp +++ b/src/whiteboard/recall.cpp @@ -71,11 +71,11 @@ recall::recall(config const& cfg, bool hidden) { // Construct and validate temp_unit_ size_t underlying_id = cfg["temp_unit_"]; - BOOST_FOREACH(unit const& recall_unit, resources::teams->at(team_index()).recall_list()) + BOOST_FOREACH(const UnitConstPtr & recall_unit, resources::teams->at(team_index()).recall_list()) { - if(recall_unit.underlying_id()==underlying_id) + if(recall_unit->underlying_id()==underlying_id) { - temp_unit_.reset(new unit(recall_unit)); + temp_unit_.reset(new unit(*recall_unit)); //TODO: is it necessary to make a copy? break; } } @@ -144,21 +144,21 @@ void recall::apply_temp_modifier(unit_map& unit_map) << "] at position " << temp_unit_->get_location() << ".\n"; //temporarily remove unit from recall list - std::vector& recalls = resources::teams->at(team_index()).recall_list(); - std::vector::iterator it = find_if_matches_id(recalls, temp_unit_->id()); + std::vector& recalls = resources::teams->at(team_index()).recall_list(); + std::vector::iterator it = find_if_matches_id(recalls, temp_unit_->id()); assert(it != recalls.end()); //Add cost to money spent on recruits. int cost = resources::teams->at(team_index()).recall_cost(); - if (it->recall_cost() > -1) { - cost = it->recall_cost(); + if ((*it)->recall_cost() > -1) { + cost = (*it)->recall_cost(); } recalls.erase(it); // Temporarily insert unit into unit_map //unit map takes ownership of temp_unit - unit_map.insert(temp_unit_.release()); + unit_map.insert(temp_unit_); resources::teams->at(team_index()).get_side_actions()->change_gold_spent_by(cost); // Update gold in top bar @@ -167,11 +167,11 @@ void recall::apply_temp_modifier(unit_map& unit_map) void recall::remove_temp_modifier(unit_map& unit_map) { - temp_unit_.reset(unit_map.extract(recall_hex_)); + temp_unit_ = unit_map.extract(recall_hex_); assert(temp_unit_.get()); //Put unit back into recall list - resources::teams->at(team_index()).recall_list().push_back(*temp_unit_); + resources::teams->at(team_index()).recall_list().push_back(temp_unit_); } void recall::draw_hex(map_location const& hex) @@ -209,7 +209,7 @@ action::error recall::check_validity() const return LOCATION_OCCUPIED; } //Check that unit to recall is still in side's recall list - const std::vector& recalls = (*resources::teams)[team_index()].recall_list(); + const std::vector& recalls = (*resources::teams)[team_index()].recall_list(); if( find_if_matches_id(recalls, temp_unit_->id()) == recalls.end() ) { return UNIT_UNAVAILABLE; } diff --git a/src/whiteboard/recall.hpp b/src/whiteboard/recall.hpp index 4ad1bad8caa1..adefd9a2e430 100644 --- a/src/whiteboard/recall.hpp +++ b/src/whiteboard/recall.hpp @@ -61,7 +61,7 @@ class recall: public action virtual map_location get_numbering_hex() const { return recall_hex_; } /** @return pointer to a copy of the recall unit. */ - virtual unit* get_unit() const { return temp_unit_.get(); } + virtual UnitPtr get_unit() const { return temp_unit_; } /** @return pointer to the fake unit used only for visuals */ virtual fake_unit_ptr get_fake_unit() { return fake_unit_; } @@ -81,7 +81,7 @@ class recall: public action virtual void do_hide(); virtual void do_show(); - std::auto_ptr temp_unit_; + UnitPtr temp_unit_; map_location recall_hex_; fake_unit_ptr fake_unit_; }; diff --git a/src/whiteboard/recruit.cpp b/src/whiteboard/recruit.cpp index 9b09727e153f..680fb6a166af 100644 --- a/src/whiteboard/recruit.cpp +++ b/src/whiteboard/recruit.cpp @@ -129,7 +129,7 @@ void recruit::apply_temp_modifier(unit_map& unit_map) // Temporarily insert unit into unit_map // unit map takes ownership of temp_unit - unit_map.insert(temp_unit_.release()); + unit_map.insert(temp_unit_); // Update gold in the top bar resources::screen->invalidate_game_status(); @@ -138,7 +138,7 @@ void recruit::apply_temp_modifier(unit_map& unit_map) void recruit::remove_temp_modifier(unit_map& unit_map) { //Unit map gives back ownership of temp_unit_ - temp_unit_.reset(unit_map.extract(recruit_hex_)); + temp_unit_ = unit_map.extract(recruit_hex_); assert(temp_unit_.get()); } @@ -164,14 +164,14 @@ void recruit::redraw() } -std::auto_ptr recruit::create_corresponding_unit() +UnitPtr recruit::create_corresponding_unit() { unit_type const* type = unit_types.find(unit_name_); assert(type); int side_num = team_index() + 1; //real_unit = false needed to avoid generating random traits and causing OOS bool real_unit = false; - std::auto_ptr result(new unit(*type, side_num, real_unit)); + UnitPtr result(new unit(*type, side_num, real_unit)); result->set_movement(0, true); result->set_attacks(0); return result; //ownership gets transferred to returned auto_ptr copy diff --git a/src/whiteboard/recruit.hpp b/src/whiteboard/recruit.hpp index b00246b6ed6e..6b77d4969020 100644 --- a/src/whiteboard/recruit.hpp +++ b/src/whiteboard/recruit.hpp @@ -65,7 +65,7 @@ class recruit: public action virtual map_location get_numbering_hex() const { return recruit_hex_; } /** @return pointer to a fake unit representing the one that will eventually be recruited. */ - virtual unit* get_unit() const { return temp_unit_.get(); } + virtual UnitPtr get_unit() const { return temp_unit_; } /** @return pointer to the fake unit used only for visuals */ virtual fake_unit_ptr get_fake_unit() { return fake_unit_; } @@ -82,7 +82,7 @@ class recruit: public action std::string unit_name_; map_location recruit_hex_; //Temp unit to insert in the future unit map when needed - std::auto_ptr temp_unit_; + UnitPtr temp_unit_; fake_unit_ptr fake_unit_; int cost_; @@ -92,7 +92,7 @@ class recruit: public action virtual void do_hide(); virtual void do_show(); - std::auto_ptr create_corresponding_unit(); + UnitPtr create_corresponding_unit(); }; std::ostream& operator<<(std::ostream& s, recruit_ptr recruit); diff --git a/src/whiteboard/side_actions.cpp b/src/whiteboard/side_actions.cpp index 819bc821371c..54d71901e773 100644 --- a/src/whiteboard/side_actions.cpp +++ b/src/whiteboard/side_actions.cpp @@ -453,9 +453,9 @@ namespace move_ptr second_; void check_recruit_recall(const map_location &loc) { - unit const* leader = second_->get_unit(); + const UnitConstPtr leader = second_->get_unit(); if(leader->can_recruit() && can_recruit_on(*leader, loc)) { - if(unit const* backup_leader = find_backup_leader(*leader)) { + if(const UnitConstPtr backup_leader = find_backup_leader(*leader)) { side_actions::iterator it = sa_.find_first_action_of(*backup_leader); if(!(it == sa_.end() || position_ < it)) { return; //backup leader but he moves before us, refuse bump @@ -487,9 +487,9 @@ side_actions::iterator side_actions::bump_earlier(side_actions::iterator positio side_actions::iterator previous = position - 1; //Verify we're not moving an action out-of-order compared to other action of the same unit - unit const* previous_ptr = (*previous)->get_unit(); - unit const* current_ptr = (*position)->get_unit(); - if(previous_ptr && current_ptr && previous_ptr == current_ptr) { + const UnitConstPtr previous_ptr = (*previous)->get_unit(); + const UnitConstPtr current_ptr = (*position)->get_unit(); + if(previous_ptr && current_ptr && previous_ptr.get() == current_ptr.get()) { return end(); } @@ -859,16 +859,16 @@ side_actions::net_cmd side_actions::make_net_cmd_refresh() const void side_actions::raw_turn_shift() { //find units who still have plans for turn 0 (i.e. were too lazy to finish their jobs) - std::set lazy_units; + std::set lazy_units; BOOST_FOREACH(action_ptr const& act, iter_turn(0)) { - unit const* u = act->get_unit(); + UnitConstPtr u = act->get_unit(); if(u) { lazy_units.insert(u); } } //push their plans back one turn - std::set::iterator lazy_end = lazy_units.end(); + std::set::iterator lazy_end = lazy_units.end(); iterator itor = end(); while(itor != begin()) { --itor; diff --git a/src/whiteboard/suppose_dead.cpp b/src/whiteboard/suppose_dead.cpp index 1774cb57febf..1d903768275b 100644 --- a/src/whiteboard/suppose_dead.cpp +++ b/src/whiteboard/suppose_dead.cpp @@ -96,13 +96,13 @@ suppose_dead::~suppose_dead() resources::screen->invalidate(loc_); } -unit* suppose_dead::get_unit() const +UnitPtr suppose_dead::get_unit() const { unit_map::iterator itor = resources::units->find(unit_underlying_id_); if (itor.valid()) - return &*itor; + return itor.get_shared_ptr(); else - return NULL; + return UnitPtr(); } void suppose_dead::accept(visitor& v) @@ -116,12 +116,12 @@ void suppose_dead::execute(bool& success, bool& complete) void suppose_dead::apply_temp_modifier(unit_map& unit_map) { // Remove the unit - unit const* removed_unit = unit_map.extract(loc_); + const UnitConstPtr removed_unit = unit_map.extract(loc_); DBG_WB << "Suppose dead: Temporarily removing unit " << removed_unit->name() << " [" << removed_unit->id() << "] from (" << loc_ << ")\n"; // Just check to make sure we removed the unit we expected to remove - assert(get_unit() == removed_unit); + assert(get_unit().get() == removed_unit.get()); } void suppose_dead::remove_temp_modifier(unit_map& unit_map) diff --git a/src/whiteboard/suppose_dead.hpp b/src/whiteboard/suppose_dead.hpp index a7fa6a682f73..1b33bf1ba087 100644 --- a/src/whiteboard/suppose_dead.hpp +++ b/src/whiteboard/suppose_dead.hpp @@ -35,7 +35,7 @@ class suppose_dead: public action virtual ~suppose_dead(); /** Return the unit targeted by this action. Null if unit doesn't exist. */ - virtual unit* get_unit() const; + virtual UnitPtr get_unit() const; /** @return null pointer */ virtual fake_unit_ptr get_fake_unit() { return fake_unit_ptr(); } /** Return the location at which this action was planned. */ diff --git a/src/whiteboard/utility.cpp b/src/whiteboard/utility.cpp index 48576030b80f..d50f2859b099 100644 --- a/src/whiteboard/utility.cpp +++ b/src/whiteboard/utility.cpp @@ -61,19 +61,19 @@ side_actions_ptr current_side_actions() return side_actions; } -unit const* find_backup_leader(unit const& leader) +UnitConstPtr find_backup_leader(const unit & leader) { assert(leader.can_recruit()); assert(resources::gameboard->map().is_keep(leader.get_location())); - BOOST_FOREACH(unit const& unit, *resources::units) + for (unit_map::const_iterator unit = resources::units->begin(); unit != resources::units->end(); unit++) { - if (unit.can_recruit() && unit.id() != leader.id()) + if (unit->can_recruit() && unit->id() != leader.id()) { - if ( can_recruit_on(unit, leader.get_location()) ) - return &unit; + if ( can_recruit_on(*unit, leader.get_location()) ) + return unit.get_shared_ptr(); } } - return NULL; + return UnitConstPtr(); } unit* find_recruiter(size_t team_index, map_location const& hex) diff --git a/src/whiteboard/utility.hpp b/src/whiteboard/utility.hpp index 3794bc13e1be..cc8d7f51fd96 100644 --- a/src/whiteboard/utility.hpp +++ b/src/whiteboard/utility.hpp @@ -47,7 +47,7 @@ side_actions_ptr current_side_actions(); * For a given leader on a keep, find another leader on another keep in the same castle. * @retval NULL if no such leader has been found */ -unit const* find_backup_leader(unit const& leader); +UnitConstPtr find_backup_leader(unit const& leader); /** * @return a leader from the specified team who can recruit on the specified hex