fixup halos segfaulting

fixes up commit 82c6b98907

Use smart "handles" for halos which have been added to a halo
manager. The handles remember what manager they came from, and
delete themselves automatically on destruction.

This wasn't an issue when haloes were basically managed by a
C library, but if we want to get rid of the static singleton
system, the handles need to be smarter than just int's.
This commit is contained in:
Chris Beck 2014-06-26 22:17:54 -04:00
parent 673c44512f
commit a226e6dc10
11 changed files with 138 additions and 82 deletions

View file

@ -101,7 +101,7 @@ void display::parse_team_overlays()
void display::add_overlay(const map_location& loc, const std::string& img, const std::string& halo,const std::string& team_name, bool visible_under_fog)
{
if (resources::halo) {
const int halo_handle = resources::halo->add(get_location_x(loc) + hex_size() / 2,
const halo::handle halo_handle = resources::halo->add(get_location_x(loc) + hex_size() / 2,
get_location_y(loc) + hex_size() / 2, halo, loc);
const overlay item(img, halo, halo_handle, team_name, visible_under_fog);
@ -111,38 +111,36 @@ void display::add_overlay(const map_location& loc, const std::string& img, const
void display::remove_overlay(const map_location& loc)
{
/* This code no longer needed because of RAII in halo::handles
if (resources::halo) {
typedef overlay_map::const_iterator Itor;
std::pair<Itor,Itor> itors = overlays_->equal_range(loc);
while(itors.first != itors.second) {
resources::halo->remove(itors.first->second.halo_handle);
++itors.first;
}
overlays_->erase(loc);
}
*/
overlays_->erase(loc);
}
void display::remove_single_overlay(const map_location& loc, const std::string& toDelete)
{
if (resources::halo) {
//Iterate through the values with key of loc
typedef overlay_map::iterator Itor;
overlay_map::iterator iteratorCopy;
std::pair<Itor,Itor> itors = overlays_->equal_range(loc);
while(itors.first != itors.second) {
//If image or halo of overlay struct matches toDelete, remove the overlay
if(itors.first->second.image == toDelete || itors.first->second.halo == toDelete) {
iteratorCopy = itors.first;
++itors.first;
resources::halo->remove(iteratorCopy->second.halo_handle);
overlays_->erase(iteratorCopy);
}
else {
++itors.first;
}
//Iterate through the values with key of loc
typedef overlay_map::iterator Itor;
overlay_map::iterator iteratorCopy;
std::pair<Itor,Itor> itors = overlays_->equal_range(loc);
while(itors.first != itors.second) {
//If image or halo of overlay struct matches toDelete, remove the overlay
if(itors.first->second.image == toDelete || itors.first->second.halo == toDelete) {
iteratorCopy = itors.first;
++itors.first;
//Not needed because of RAII -->resources::halo->remove(iteratorCopy->second.halo_handle);
overlays_->erase(iteratorCopy);
}
else {
++itors.first;
}
}
}

View file

@ -28,6 +28,8 @@
namespace halo
{
const int NO_HALO = 0;
class halo_impl
{
@ -465,27 +467,24 @@ void halo_impl::render()
manager::manager(display& screen) : impl_(new halo_impl(screen))
{}
manager::~manager()
{
delete impl_;
}
int manager::add(int x, int y, const std::string& image, const map_location& loc,
handle manager::add(int x, int y, const std::string& image, const map_location& loc,
ORIENTATION orientation, bool infinite)
{
return impl_->add(x,y,image, loc, orientation, infinite);
int new_halo = impl_->add(x,y,image, loc, orientation, infinite);
return handle(new halo_record(new_halo, impl_));
}
/** Set the position of an existing haloing effect, according to its handle. */
void manager::set_location(int handle, int x, int y)
void manager::set_location(const handle & h, int x, int y)
{
impl_->set_location(handle,x,y);
impl_->set_location(h->id_,x,y);
}
/** Remove the halo with the given handle. */
void manager::remove(int handle)
void manager::remove(const handle & h)
{
impl_->remove(handle);
impl_->remove(h->id_);
h->id_ = NO_HALO;
}
/**
@ -506,4 +505,34 @@ void manager::render()
// end halo::manager implementation
/**
* halo::halo_record implementation
*/
halo_record::halo_record() :
id_(NO_HALO), //halo::NO_HALO
my_manager_()
{}
halo_record::halo_record(int id, const boost::shared_ptr<halo_impl> & my_manager) :
id_(id),
my_manager_(my_manager)
{}
halo_record::~halo_record()
{
if (id_ == NO_HALO) return;
if (my_manager_.expired()) return;
boost::shared_ptr<halo_impl> man = my_manager_.lock();
if (man) {
try {
man->remove(id_);
} catch (std::exception & e) {
std::cerr << "Caught an exception in halo::halo_record destructor: \n" << e.what() << std::endl;
} catch (...) {}
}
}
} //end namespace halo

View file

@ -21,19 +21,25 @@ class display;
#include "map_location.hpp"
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
namespace halo
{
class halo_impl;
class halo_record;
typedef boost::shared_ptr<halo_record> handle;
enum ORIENTATION { NORMAL, HREVERSE, VREVERSE, HVREVERSE };
const int NO_HALO = 0;
class manager
{
public:
manager(display& disp);
~manager();
/**
* Add a haloing effect using 'image centered on (x,y).
@ -44,14 +50,14 @@ public:
* shroud is active. (Note it will be shown with the fog active.)
* If it is not attached to an item, the location should be set to -1, -1
*/
int add(int x, int y, const std::string& image, const map_location& loc,
handle add(int x, int y, const std::string& image, const map_location& loc,
halo::ORIENTATION orientation=NORMAL, bool infinite=true);
/** Set the position of an existing haloing effect, according to its handle. */
void set_location(int handle, int x, int y);
void set_location(const handle & h, int x, int y);
/** Remove the halo with the given handle. */
void remove(int handle);
void remove(const handle & h);
/**
* Render and unrender haloes.
@ -63,7 +69,46 @@ public:
void render();
private:
halo_impl * impl_;
boost::shared_ptr<halo_impl> impl_;
};
/**
* RAII object which manages a halo. When it goes out of scope it removes the corresponding halo entry.
*/
class halo_record : public boost::noncopyable
{
public:
halo_record();
halo_record(int id, const boost::shared_ptr<halo_impl> & my_manager);
~halo_record();
friend class manager;
private:
int id_;
boost::weak_ptr<halo_impl> my_manager_;
//Begin safe_bool impl
#ifndef HAVE_CXX11
struct safe_bool_impl { void nonnull() {} };
/**
* Used as t he return type of the conversion operator for boolean contexts.
* Needed, since the compiler would otherwise consider the following
* conversion (C legacy): cfg["abc"] -> "abc"[bool(cfg)] -> 'b'
*/
typedef void (safe_bool_impl::*safe_bool)();
#endif
public:
#ifdef HAVE_CXX11
explicit operator bool() const
{ return id_ != 0 && !my_manager_.expired(); }
#else
operator safe_bool() const
{ return (id_ != 0 && !my_manager_.expired()) ? &safe_bool_impl::nonnull : NULL; }
#endif
};
} // end namespace halo

View file

@ -15,11 +15,13 @@
#ifndef OVERLAY_INCLUDED
#define OVERLAY_INCLUDED
#include "halo.hpp"
struct overlay
{
overlay(const std::string& img, const std::string& halo_img,
int handle, const std::string& overlay_team_name, const bool fogged) : image(img), halo(halo_img),
halo::handle handle, const std::string& overlay_team_name, const bool fogged) : image(img), halo(halo_img),
team_name(overlay_team_name), halo_handle(handle) , visible_in_fog(fogged)
{}
@ -27,7 +29,7 @@ struct overlay
overlay(const config& cfg) :
image(cfg["image"]), halo(cfg["halo"]), team_name(cfg["team_name"]),
name(cfg["name"].t_str()), id(cfg["id"]),
halo_handle(-1), visible_in_fog(cfg["visible_in_fog"].to_bool())
halo_handle(), visible_in_fog(cfg["visible_in_fog"].to_bool())
{
}
@ -37,7 +39,7 @@ struct overlay
t_string name;
std::string id;
int halo_handle;
halo::handle halo_handle;
bool visible_in_fog;
};

View file

@ -874,7 +874,7 @@ unit_animation::particule::particule(
animated<unit_frame>(),
accelerate(true),
parameters_(),
halo_id_(0),
halo_id_(),
last_frame_begin_time_(0),
cycles_(false)
{
@ -1226,19 +1226,14 @@ void unit_animation::particule::redraw(const frame_parameters& value,const map_l
// for sound frames we want the first time variable set only after the frame has started.
if(get_current_frame_begin_time() != last_frame_begin_time_ && animation_time >= get_current_frame_begin_time()) {
last_frame_begin_time_ = get_current_frame_begin_time();
current_frame.redraw(get_current_frame_time(),true,in_scope_of_frame,src,dst,&halo_id_,default_val,value);
current_frame.redraw(get_current_frame_time(),true,in_scope_of_frame,src,dst,halo_id_,default_val,value);
} else {
current_frame.redraw(get_current_frame_time(),false,in_scope_of_frame,src,dst,&halo_id_,default_val,value);
current_frame.redraw(get_current_frame_time(),false,in_scope_of_frame,src,dst,halo_id_,default_val,value);
}
}
void unit_animation::particule::clear_halo()
{
if(halo_id_ != halo::NO_HALO) {
if (resources::halo) {
resources::halo->remove(halo_id_);
}
halo_id_ = halo::NO_HALO;
}
halo_id_ = halo::handle(); // halo::NO_HALO
}
std::set<map_location> unit_animation::particule::get_overlaped_hex(const frame_parameters& value,const map_location &src, const map_location &dst)
{
@ -1250,18 +1245,12 @@ std::set<map_location> unit_animation::particule::get_overlaped_hex(const frame_
unit_animation::particule::~particule()
{
if (resources::halo) {
resources::halo->remove(halo_id_);
}
halo_id_ = halo::NO_HALO;
halo_id_ = halo::handle(); // halo::NO_HALO
}
void unit_animation::particule::start_animation(int start_time)
{
if (resources::halo) {
resources::halo->remove(halo_id_);
}
halo_id_ = halo::NO_HALO;
halo_id_ = halo::handle(); // halo::NO_HALO
parameters_.override(get_animation_duration());
animated<unit_frame>::start_animation(start_time,cycles_);
last_frame_begin_time_ = get_begin_time() -1;

View file

@ -16,6 +16,7 @@
#include "animated.hpp"
#include "config.hpp"
#include "halo.hpp"
#include "unit_frame.hpp"
#include "unit_ptr.hpp"
@ -89,7 +90,7 @@ class unit_animation
animated<unit_frame>(start_time),
accelerate(true),
parameters_(builder),
halo_id_(0),
halo_id_(),
last_frame_begin_time_(0),
cycles_(false)
{}
@ -119,7 +120,7 @@ class unit_animation
//animation params that can be locally overridden by frames
frame_parsed_parameters parameters_;
int halo_id_;
halo::handle halo_id_;
int last_frame_begin_time_;
bool cycles_;

View file

@ -18,7 +18,6 @@
#include "display.hpp"
#include "map.hpp"
#include "preferences.hpp"
#include "resources.hpp" //only for halo::manager
#include "unit_animation.hpp"
#include "unit.hpp"
#include "unit_types.hpp"
@ -149,12 +148,7 @@ void unit_animation_component::refresh()
void unit_animation_component::clear_haloes ()
{
if(unit_halo_ != halo::NO_HALO) {
if (resources::halo) {
resources::halo->remove(unit_halo_);
}
unit_halo_ = halo::NO_HALO;
}
unit_halo_ = halo::handle(); //halo::NO_HALO; <-- Removes it from the halo manager automatically.
if(anim_ ) anim_->clear_haloes();
}

View file

@ -46,7 +46,7 @@ public:
frame_begin_time_(0),
draw_bars_(false),
refreshing_(false),
unit_halo_(halo::NO_HALO) {}
unit_halo_() {}
/** Copy construct a unit animation component, for use when copy constructing a unit. */
unit_animation_component(unit & my_unit, const unit_animation_component & o) :
@ -58,7 +58,7 @@ public:
frame_begin_time_(o.frame_begin_time_),
draw_bars_(o.draw_bars_),
refreshing_(o.refreshing_),
unit_halo_(halo::NO_HALO) {}
unit_halo_() {}
/** Chooses an appropriate animation from the list of known animations. */
const unit_animation* choose_animation(const display& disp,
@ -123,7 +123,7 @@ private:
bool draw_bars_; //!< bool indicating whether to draw bars with the unit
bool refreshing_; //!< avoid infinite recursion. flag used for drawing / animation
int unit_halo_; //!< flag used for drawing / animation
halo::handle unit_halo_; //!< handle to the halo of this unit
};
#endif

View file

@ -161,13 +161,13 @@ void unit_drawer::redraw_unit (const unit & u) const
const int x = static_cast<int>(adjusted_params.offset * xdst + (1.0-adjusted_params.offset) * xsrc) + hex_size_by_2;
const int y = static_cast<int>(adjusted_params.offset * ydst + (1.0-adjusted_params.offset) * ysrc) + hex_size_by_2;
if(ac.unit_halo_ == halo::NO_HALO && !u.image_halo().empty()) {
if(!ac.unit_halo_ && !u.image_halo().empty()) {
ac.unit_halo_ = halo_man.add(0, 0, u.image_halo()+u.TC_image_mods(), map_location(-1, -1));
}
if(ac.unit_halo_ != halo::NO_HALO && u.image_halo().empty()) {
if(ac.unit_halo_ && u.image_halo().empty()) {
halo_man.remove(ac.unit_halo_);
ac.unit_halo_ = halo::NO_HALO;
} else if(ac.unit_halo_ != halo::NO_HALO) {
ac.unit_halo_ = halo::handle(); //halo::NO_HALO;
} else if(ac.unit_halo_) {
halo_man.set_location(ac.unit_halo_, x, y - height_adjust);
}

View file

@ -628,7 +628,7 @@ std::vector<std::string> frame_parsed_parameters::debug_strings() const {
}
void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of_frame,const map_location & src,const map_location & dst,int*halo_id,const frame_parameters & animation_val,const frame_parameters & engine_val)const
void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of_frame,const map_location & src,const map_location & dst,halo::handle & halo_id,const frame_parameters & animation_val,const frame_parameters & engine_val)const
{
const int xsrc = game_display::get_singleton()->get_location_x(src);
const int ysrc = game_display::get_singleton()->get_location_y(src);
@ -698,10 +698,7 @@ void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of
ftofxp(current_data.highlight_ratio), current_data.blend_with,
current_data.blend_ratio,current_data.submerge,!facing_north);
}
if (resources::halo) {
resources::halo->remove(*halo_id);
}
*halo_id = halo::NO_HALO;
halo_id = halo::handle(); //halo::NO_HALO;
if (!in_scope_of_frame) { //check after frame as first/last frame image used in defense/attack anims
return;
@ -744,13 +741,13 @@ void unit_frame::redraw(const int frame_time,bool on_start_time,bool in_scope_of
}
if(direction != map_location::SOUTH_WEST && direction != map_location::NORTH_WEST) {
*halo_id = resources::halo->add(static_cast<int>(x+current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
halo_id = resources::halo->add(static_cast<int>(x+current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
static_cast<int>(y+current_data.halo_y* game_display::get_singleton()->get_zoom_factor()),
current_data.halo + current_data.halo_mod,
map_location(-1, -1),
orientation);
} else {
*halo_id = resources::halo->add(static_cast<int>(x-current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
halo_id = resources::halo->add(static_cast<int>(x-current_data.halo_x* game_display::get_singleton()->get_zoom_factor()),
static_cast<int>(y+current_data.halo_y* game_display::get_singleton()->get_zoom_factor()),
current_data.halo + current_data.halo_mod,
map_location(-1, -1),

View file

@ -20,6 +20,7 @@
#ifndef UNIT_FRAME_H_INCLUDED
#define UNIT_FRAME_H_INCLUDED
#include "halo.hpp"
#include "image.hpp"
class config;
@ -204,7 +205,7 @@ class unit_frame {
public:
// Constructors
unit_frame(const frame_builder& builder=frame_builder()):builder_(builder){}
void redraw(const int frame_time,bool on_start_time,bool in_scope_of_frame,const map_location & src,const map_location & dst,int*halo_id,const frame_parameters & animation_val,const frame_parameters & engine_val)const;
void redraw(const int frame_time,bool on_start_time,bool in_scope_of_frame,const map_location & src,const map_location & dst,halo::handle & halo_id,const frame_parameters & animation_val,const frame_parameters & engine_val)const;
const frame_parameters merge_parameters(int current_time,const frame_parameters & animation_val,const frame_parameters & engine_val=frame_parameters()) const;
const frame_parameters parameters(int current_time) const {return builder_.parameters(current_time);}
const frame_parameters end_parameters() const {return builder_.parameters(duration());}