[C++-sig] Boost Python loss of values

Jay Riley super24bitsound at hotmail.com
Thu Aug 25 13:17:34 CEST 2011


I'm having a really weird issue in boost python. I'm focusing on a particular property/method to simplify the example. Here's the situation:

In my program, I have a class called Attack. With the following layout (simplified for example)

    class Attack : public Action
    {
    public:
        virtual int CalculateDamage(const std::vector<BattleCharacter*>& users, BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, BattleField *field);
    protected:
        bool Hit;
    }

I exposed Attack to python, making it overridable, as follows:

    struct AttackWrapper : Game::Battles::Actions::Attack
    {
        int AttackWrapper::CalculateDamage(const std::vector<Game::Battles::BattleCharacter*>& users, Game::Battles::BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField *field)
        {
               return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));
        }
        int AttackWrapper::CalculateDamageDefault(const std::vector<Game::Battles::BattleCharacter*>& users, Game::Battles::BattleCharacter* target, const std::vector<Actions::ActionTarget>& targets, Game::Battles::BattleField *field)
        {
            return this->Attack::CalculateDamage(users, target, Targets, field);
        }
    }

And the python exposing is done as follows:

    class_<Attack, AttackWrapper, boost::shared_ptr<Attack>, bases<Action> >("Attack")
        .def("CalculateDamage", &AttackWrapper::CalculateDamageDefault);


I initially thought everything was working fine, as I can override the `CalculateDamage` method within python and have it work correctly. However, When I want to use the normal `Attack->CalculateDamage`, the following happens:

I only call `CalculateDamage` when Hit is true, and I can confirm via break point when I hit this line, Hit is true:

    return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));

Now, because I haven't overriden `CalculateDamage` in Python for this attack instance, it ends up resolving to `AttackWrapper::CalculateDamageDefault`. But by the time I enter AttackWrapper::CalculateDamageDefault, Hit is no longer true. That is, when I break on this line:

    return this->Attack::CalculateDamage(users, target, Targets, field);

Hit is false. So somewhere between 

    return call_method<int>(self, "CalculateDamage", users, ptr(target), targets, ptr(field));

resolving to 

    return this->Attack::CalculateDamage(users, target, Targets, field);

my property's value is lost. I have no idea what could be causing this. Has anyone encountered something like this before?

The attacks I'm using for testing are defined as follows:

class ScriptedAttack(Attack):
    def __init__(self, Type, ID, Name, Flags, Targs = ActionTargets.Any, AllowTargettingOverride = False, Power = 0, MPCost = 0, SPCost = 0, Accuracy = 0.9, CritChance = 0.1, DefineOwnUse = False, EleWeights = None, StatusEffectChances = None):
        if (EleWeights == None and StatusEffectChances == None):
            Attack.__init__(self, Type, ID, Name, Flags, Targs, AllowTargettingOVerride, Power, MPCost, SPCost, Accuracy, CritChance, DefineOwnUse)
        else:
            Elemap = ElementMap()
            if (EleWeights != None):
                for Element, Weight in EleWeights.iteritems():
                    Elemap[Element] = Weight
            SEChances = SEChanceMap()
            if (StatusEffectChances != None):
                for StatusEffect, Chance in StatusEffectChances.iteritems():
                    SEChances[StatusEffect] = Chance
            Attack.__init__(self, Type, ID, Name, Flags, Elemap, Targs, AllowTargettingOverride, Power, MPCost, SPCost, Accuracy, CritChance, DefineOwnUse, SEChances)
    def Clone(self):
        return copy.deepcopy(self)

Fire = ScriptedAttack(ActionType.MagicAction, PrimaryEngine.GetUID(), "Fire", AttackFlags.Projectile | AttackFlags.Elemental, ActionTargets.Any, True, 32, 14, 0, 1.0, 0.1, False, {Elements.Fire: 1.0})
Fira = ScriptedAttack(ActionType.MagicAction, PrimaryEngine.GetUID(), "Fira", AttackFlags.Projectile | AttackFlags.Elemental, ActionTargets.Any, True, 63, 35, 0, 1.0, 0.1, False, {Elements.Fire: 1.0})

ActLibrary.AddAttack(Fire)
ActLibrary.AddAttack(Fira)

ActLibrary.AddAttack takes in a boost::shared_ptr<Attack> and stores it into a hash table. I lookup the attack and use the instance stored there to do CalculateDamage.

It almost seems like the object is being copied, but I have no idea why that'd be so.

Any help would be appreciated.

Thanks
 		 	   		  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20110825/f9b21d5b/attachment.html>


More information about the Cplusplus-sig mailing list