开发者

boost::python - how to pass by reference/pointer to python overriden class functions

I have some class functions that takes in parameters by pointer. However, when I expose and override these functions in boost::python, any changes I make to the parameters are not reflected back to the original, meaning it isn't being passed by pointer as I expected. I previously had them as pass-by-reference, but the same problem still occurred. For an example of what I mean, here's some of my code with unimportant functions and details omitted.

class StatusEffect
{
public:
      virtual void TickCharacter(Character::BaseCharacter* character, Battles::BattleField *field, int ticks = 1);
}
//In my Scripting Code header file

struct StatusEffectWrapper : Game::StatusEffects::StatusEffect
{
    virtual void TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks = 1);
    virtual void TickCharacterDefault(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks = 1);
}
//In the actual scripting code
    void StatusEffectWrapper::TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
    {
        call_method<void>(self, "TickCharacter", character, field, ticks);
    }
    void StatusEffectWrapper::TickCharacterDefault(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
    {
        this->StatusEffect::TickCharacter(character, field, ticks);
    }

    class_<StatusEffects::StatusEffect, boost::shared_ptr<StatusEffectWrapper> >("StatusEffect")
    .def("TickCharacter", &StatusEffect::TickCharacter, &StatusEffectWrapper::TickCharacterDefault)

and finally in my Python file, I try and do something like this

class StatCreepEffect(StatusEffect):
    def __init__(self, name, stat_, rate_, descript, uid, turns, prior, canrefresh, poseffect, cats, conds, flgs, sep, pers):
        StatusEffect.__init__(self, name, descript, uid, turns, prior, canrefresh, poseffect, cats, conds, flgs, sep, pers)
        self.rate = rate_
        self.stat = stat_
    def TickCharacter(self, Character, Field, Ticks):
        if (self.stat == Stat.HP):
            Character.SetHP(int(round(Character.GetHP() + Character.GetInBattleStat(self.stat) * self.rate)))
            print("HP Regenerated on character " + Character.GetName() + " New HP: " + str(Character.GetHP()))
        elif (self.stat == Stat.MP):
            Character.SetMP(int(round(Character.GetMP() + Character.GetInBattleStat(self.stat) * self.rate)))
        elif (self.stat == Stat.SP):
            Character.SetSP(int(round(Character.SetSP() + Character.GetInBattleStat(self.stat) * self.rate)))

Regen = StatCreepEffect("Regen", Stat.HP, 0.05, "Regenerates a small amount of HP every turn", PrimaryEngine.GetUID(), 14, 0, True, True, StatusCategories.SC_Regen, 0, StatusFlags.TickEffect, True, StatusPersistence.SP_Timer_Cure)

SELibrary.AddPythonEffect(Regen);

I call the effect like so in my C++ code

StatusEffect* regen = game.GetSELibrary().GetStatusEffect(std::string("Regen"));
while(character.GetHP() < 600)
    {
regen->TickCharacter(&character, &field, 1);
        std::cout << "Character HP: " << character.GetHP() << std::endl;
    }

I created this code following the example here http://wiki.python.org/moin/boost.python/OverridableVirtualFunctions

The script compiles and the effect is added correctly. The print line in the python script prints the correct value. The character object starts with 400 HP and the print line outputs 430. However, the std::cout line in my C++ code always outputs 400, meaning the extra 30 HP added by the script is not reflected back in the original object. For clarity, here's the console output from the above C++ code fragment:

HP Regenerated on character Arian New HP: 430
Character HP: 400

Can someone help me figure out how to make this work correctly? It'd be greatly appreciated.

Thanks

If it matters, the AddPythonEffect is defined as follows:

void StatusEff开发者_如何学GoectsLibrary::AddPythonEffect(boost::shared_ptr<StatusEffect> effect)
{
    if (effect.get() != nullptr)
    {
        NameToSEMap[effect->GetName()] = effect;
        IDToSEMap[effect->GetUID()] = effect;
    }
}


Well after searching around for a bit I found the answer. Turns out you have to explicitly indicate to call_method not to make a copy when it's pass by reference (by using ref(T)) or pointer (by using ptr(T)). By Changing

void StatusEffectWrapper::TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
{
    call_method<void>(self, "TickCharacter", character, field, ticks);
}

to

void StatusEffectWrapper::TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
{
    call_method<void>(self, "TickCharacter", ptr(character), ptr(field), ticks);
}

I get the behavour I want.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜