Skip to content

Commit

Permalink
Turned the use of script object back to new allocated pointers.
Browse files Browse the repository at this point in the history
This was partly the former use of it, and it took me time to figure out
why.

Some crashes at app exit were thus caused by my changes, but also
by other code part. This should lessen the crashes seen at app exit
a lot, even if luabind can still cause a crash in lua for a reason
I'm not aware of.
  • Loading branch information
Yohann Ferreira committed Nov 2, 2012
1 parent 1026991 commit a86034a
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 89 deletions.
6 changes: 4 additions & 2 deletions src/common/global/global_objects.cpp
Expand Up @@ -133,8 +133,10 @@ GlobalItem::GlobalItem(uint32 id, uint32 count) :
_warmup_time = script_file.ReadUInt("warmup_time");
_cooldown_time = script_file.ReadUInt("cooldown_time");

_battle_use_function = script_file.ReadFunctionPointer("BattleUse");
_field_use_function = script_file.ReadFunctionPointer("FieldUse");
_battle_use_function = new ScriptObject();
*_battle_use_function = script_file.ReadFunctionPointer("BattleUse");
_field_use_function = new ScriptObject();
*_field_use_function = script_file.ReadFunctionPointer("FieldUse");

script_file.CloseTable();
if(script_file.IsErrorDetected()) {
Expand Down
30 changes: 14 additions & 16 deletions src/common/global/global_objects.h
Expand Up @@ -211,14 +211,12 @@ class GlobalItem : public GlobalObject
}

//! \brief Returns true if the item can be used in battle
bool IsUsableInBattle() {
return _battle_use_function.is_valid();
}
bool IsUsableInBattle()
{ return (_battle_use_function && _battle_use_function->is_valid()); }

//! \brief Returns true if the item can be used in the field
bool IsUsableInField() {
return _field_use_function.is_valid();
}
bool IsUsableInField()
{ return (_field_use_function && _field_use_function->is_valid()); }

//! \name Class Member Access Functions
//@{
Expand All @@ -229,16 +227,14 @@ class GlobalItem : public GlobalObject
/** \brief Returns a pointer to the ScriptObject of the battle use function
*** \note This function will return NULL if the skill is not usable in battle
**/
const ScriptObject &GetBattleUseFunction() const {
return _battle_use_function;
}
ScriptObject* GetBattleUseFunction() const
{ return _battle_use_function; }

/** \brief Returns a pointer to the ScriptObject of the field use function
*** \note This function will return NULL if the skill is not usable in the field
**/
const ScriptObject &GetFieldUseFunction() const {
return _field_use_function;
}
ScriptObject* GetFieldUseFunction() const
{ return _field_use_function; }

/** \brief Returns Warmup time needed before using this item in battles.
**/
Expand All @@ -257,11 +253,13 @@ class GlobalItem : public GlobalObject
//! \brief The type of target for the item
GLOBAL_TARGET _target_type;

//! \brief A reference to the script function that performs the item's effect while in battle
ScriptObject _battle_use_function;
//! \brief A pointer to the script function that performs the item's effect while in battle
//! Do not delete it. Luabind's garbage collector will handle it.
ScriptObject *_battle_use_function;

//! \brief A reference to the script function that performs the item's effect while in a menu
ScriptObject _field_use_function;
//! \brief A pointer to the script function that performs the item's effect while in a menu
//! Do not delete it. Luabind's garbage collector will handle it.
ScriptObject *_field_use_function;

//! \brief The warmup time in milliseconds needed before using this item in battles.
uint32 _warmup_time;
Expand Down
10 changes: 6 additions & 4 deletions src/common/global/global_skills.cpp
Expand Up @@ -77,8 +77,10 @@ GlobalSkill::GlobalSkill(uint32 id) :
_action_name = skill_script->ReadString("action_name");
_target_type = static_cast<GLOBAL_TARGET>(skill_script->ReadInt("target_type"));

_battle_execute_function = skill_script->ReadFunctionPointer("BattleExecute");
_field_execute_function = skill_script->ReadFunctionPointer("FieldExecute");
_battle_execute_function = new ScriptObject();
*_battle_execute_function = skill_script->ReadFunctionPointer("BattleExecute");
_field_execute_function = new ScriptObject();
*_field_execute_function = skill_script->ReadFunctionPointer("FieldExecute");

// Read all the battle animation scripts linked to this skill, if any
if(skill_script->DoesTableExist("animation_scripts")) {
Expand Down Expand Up @@ -146,13 +148,13 @@ GlobalSkill &GlobalSkill::operator=(const GlobalSkill &copy)

bool GlobalSkill::ExecuteBattleFunction(private_battle::BattleActor *user, private_battle::BattleTarget target)
{
if(!_battle_execute_function.is_valid()) {
if(!_battle_execute_function->is_valid()) {
IF_PRINT_WARNING(BATTLE_DEBUG) << "Can't execute invalid battle script function." << std::endl;
return false;
}

try {
ScriptCallFunction<void>(_battle_execute_function, user, target);
ScriptCallFunction<void>(*_battle_execute_function, user, target);
} catch(const luabind::error &err) {
ScriptManager->HandleLuaError(err);
return false;
Expand Down
30 changes: 14 additions & 16 deletions src/common/global/global_skills.h
Expand Up @@ -69,14 +69,12 @@ class GlobalSkill
}

//! \brief Returns true if the skill can be executed in battles
bool IsExecutableInBattle() const {
return _battle_execute_function.is_valid();
}
bool IsExecutableInBattle() const
{ return (_battle_execute_function && _battle_execute_function->is_valid()); }

//! \brief Returns true if the skill can be executed in menus
bool IsExecutableInField() const {
return _field_execute_function.is_valid();
}
bool IsExecutableInField() const
{ return (_field_execute_function && _field_execute_function->is_valid()); }

/** \name Class member access functions
*** \note No set functions are defined because the class members should only be intialized within Lua
Expand Down Expand Up @@ -125,19 +123,17 @@ class GlobalSkill
/** \brief Returns a pointer to the ScriptObject of the battle execution function
*** \note This function will return NULL if the skill is not executable in battle
**/
const ScriptObject &GetBattleExecuteFunction() const {
return _battle_execute_function;
}
ScriptObject* GetBattleExecuteFunction() const
{ return _battle_execute_function; }

//! Execute the corresponding skill Battle function
bool ExecuteBattleFunction(hoa_battle::private_battle::BattleActor *user, hoa_battle::private_battle::BattleTarget target);

/** \brief Returns a pointer to the ScriptObject of the menu execution function
*** \note This function will return NULL if the skill is not executable in menus
**/
const ScriptObject &GetFieldExecuteFunction() const {
return _field_execute_function;
}
ScriptObject* GetFieldExecuteFunction() const
{ return _field_execute_function; }

/** \brief Tells the animation script filename linked to the skill for the given character,
*** Or an empty value otherwise;
Expand Down Expand Up @@ -196,11 +192,13 @@ class GlobalSkill
**/
GLOBAL_TARGET _target_type;

//! \brief A reference to the skill's execution function for battles
ScriptObject _battle_execute_function;
//! \brief A pointer to the skill's execution function for battles
//! Do not delete it. Luabind's garbage collector will handle it.
ScriptObject *_battle_execute_function;

//! \brief A reference to the skill's execution function for menus
ScriptObject _field_execute_function;
//! \brief A pointer to the skill's execution function for menus
//! Do not delete it. Luabind's garbage collector will handle it.
ScriptObject *_field_execute_function;

//! \brief map containing the animation scripts names linked to each characters id for the given skill.
std::map <uint32, std::string> _animation_scripts;
Expand Down
4 changes: 4 additions & 0 deletions src/engine/script/script_read.h
Expand Up @@ -301,6 +301,10 @@ class ReadScriptDescriptor : public ScriptDescriptor
*** if the function is embedded in a table.
*** \return A luabind::object class object, which can be used to call the function. It effectively
*** serves as a function pointer.
*** \note IMPORTANT: Even when luabind object are returned a plain variables, they must be copied in
*** a pointer member to avoid deletion, and that pointer must have allocated ots own memory space (using new ScriptObject())
*** to store the data since the luabind garbage collector might make the application
*** crash when closing the stack because of corrupted memory.
**/
//@{
luabind::object ReadFunctionPointer(const std::string &key);
Expand Down
49 changes: 36 additions & 13 deletions src/engine/script_supervisor.cpp
Expand Up @@ -35,16 +35,39 @@ void ScriptSupervisor::Initialize(hoa_mode_manager::GameMode *gm)
continue;
}

_reset_functions.push_back(scene_script.ReadFunctionPointer("Reset"));
_update_functions.push_back(scene_script.ReadFunctionPointer("Update"));
_draw_background_functions.push_back(scene_script.ReadFunctionPointer("DrawBackground"));
_draw_foreground_functions.push_back(scene_script.ReadFunctionPointer("DrawForeground"));
_draw_post_effects_functions.push_back(scene_script.ReadFunctionPointer("DrawPostEffects"));
ScriptObject *script_function = new ScriptObject();
*script_function = scene_script.ReadFunctionPointer("Reset");
if (script_function->is_valid())
_reset_functions.push_back(script_function);

script_function = new ScriptObject();
*script_function = scene_script.ReadFunctionPointer("Update");
if (script_function->is_valid())
_update_functions.push_back(script_function);

script_function = new ScriptObject();
*script_function = scene_script.ReadFunctionPointer("DrawBackground");
if (script_function->is_valid())
_draw_background_functions.push_back(script_function);

script_function = new ScriptObject();
*script_function = scene_script.ReadFunctionPointer("DrawForeground");
if (script_function->is_valid())
_draw_foreground_functions.push_back(script_function);

script_function = new ScriptObject();
*script_function = scene_script.ReadFunctionPointer("DrawPostEffects");
if (script_function->is_valid())
_draw_post_effects_functions.push_back(script_function);

// Trigger the Initialize functions in the loading order.
ScriptObject init_function = scene_script.ReadFunctionPointer("Initialize");
if(init_function.is_valid() && gm)
ScriptCallFunction<void>(init_function, gm);
// We're using a pointer to avoid auto-deleting the object since it's done by luabind's garbage collector.
// We're also allocating memory to store the temporary data returned by the ReadFunctionPointer()
// function and avoid a memory corruption.
ScriptObject * init_function = new ScriptObject();
*init_function = scene_script.ReadFunctionPointer("Initialize");
if(init_function->is_valid() && gm)
ScriptCallFunction<void>(*init_function, gm);
else
PRINT_ERROR << "Couldn't initialize the scene component" << std::endl; // Should never happen

Expand All @@ -62,7 +85,7 @@ void ScriptSupervisor::Reset()
{
// Updates custom scripts
for(uint32 i = 0; i < _reset_functions.size(); ++i)
ReadScriptDescriptor::RunScriptObject(_reset_functions[i]);
ReadScriptDescriptor::RunScriptObject(*_reset_functions[i]);
}

void ScriptSupervisor::Update()
Expand All @@ -73,28 +96,28 @@ void ScriptSupervisor::Update()

// Updates custom scripts
for(uint32 i = 0; i < _update_functions.size(); ++i)
ReadScriptDescriptor::RunScriptObject(_update_functions[i]);
ReadScriptDescriptor::RunScriptObject(*_update_functions[i]);
}


void ScriptSupervisor::DrawBackground()
{
// Handles custom scripted draw before sprites
for(uint32 i = 0; i < _draw_background_functions.size(); ++i)
ReadScriptDescriptor::RunScriptObject(_draw_background_functions[i]);
ReadScriptDescriptor::RunScriptObject(*_draw_background_functions[i]);
}


void ScriptSupervisor::DrawForeground()
{
for(uint32 i = 0; i < _draw_foreground_functions.size(); ++i)
ReadScriptDescriptor::RunScriptObject(_draw_foreground_functions[i]);
ReadScriptDescriptor::RunScriptObject(*_draw_foreground_functions[i]);
}

void ScriptSupervisor::DrawPostEffects()
{
for(uint32 i = 0; i < _draw_post_effects_functions.size(); ++i)
ReadScriptDescriptor::RunScriptObject(_draw_post_effects_functions[i]);
ReadScriptDescriptor::RunScriptObject(*_draw_post_effects_functions[i]);
}

int32 ScriptSupervisor::AddAnimation(const std::string &filename)
Expand Down
15 changes: 10 additions & 5 deletions src/engine/script_supervisor.h
Expand Up @@ -115,36 +115,41 @@ class ScriptSupervisor
//! \brief The name of the Lua files used to script this mode
std::vector<std::string> _script_filenames;

// IMPORTANT: We're using a pointer to avoid auto-deleting the object since it's done by luabind's garbage collector.
// We're also allocating memory to store the temporary data returned by the ReadFunctionPointer()
// function and avoid a memory corruption.
// Do not delete the ScriptObject pointers

/** \brief Script functions which assists with the #Reset method
*** Those functions execute any code that needs to be performed on a reset call. An example of
*** one common operation is to reset the scene state when coming back to a given mode from another.
**/
std::vector<ScriptObject> _reset_functions;
std::vector<ScriptObject*> _reset_functions;

/** \brief Script functions which assists with the #Update method
*** Those functions execute any code that needs to be performed on an update call. An example of
*** one common operation is to detect certain conditions and respond appropriately, such as
*** triggering a dialogue.
**/
std::vector<ScriptObject> _update_functions;
std::vector<ScriptObject*> _update_functions;

/** \brief Script functions which assists with the #DrawBackground method
*** Those functions execute any code that needs to be performed on a draw call.
*** This permits custom background effects.
**/
std::vector<ScriptObject> _draw_background_functions;
std::vector<ScriptObject*> _draw_background_functions;

/** \brief Script functions which assists with the #DrawForeground method
*** Those functions execute any code that needs to be performed on a draw call.
*** This permits custom visual effects over the characters and enemies sprites.
**/
std::vector<ScriptObject> _draw_foreground_functions;
std::vector<ScriptObject*> _draw_foreground_functions;

/** \brief Script functions which assists with the #DrawEffects methods
*** Those functions execute any code that needs to be performed on a draw call.
*** This permits custom effects just below the gui.
**/
std::vector<ScriptObject> _draw_post_effects_functions;
std::vector<ScriptObject*> _draw_post_effects_functions;
};

#endif
20 changes: 11 additions & 9 deletions src/modes/battle/battle_actions.cpp
Expand Up @@ -92,23 +92,25 @@ SkillAction::SkillAction(BattleActor *actor, BattleTarget target, GlobalSkill *s
return;
}

_init_function = anim_script.ReadFunctionPointer("Initialize");
_init_function = new ScriptObject();
*_init_function = anim_script.ReadFunctionPointer("Initialize");

if(!_init_function.is_valid()) {
if(!_init_function->is_valid()) {
anim_script.CloseFile();
return;
}

// Attempt to load a possible update function.
_update_function = anim_script.ReadFunctionPointer("Update");
_update_function = new ScriptObject();
*_update_function = anim_script.ReadFunctionPointer("Update");
_is_scripted = true;
anim_script.CloseFile();
}

void SkillAction::_InitAnimationScript()
{
try {
ScriptCallFunction<void>(_init_function, _actor, _target, _skill);
ScriptCallFunction<void>(*_init_function, _actor, _target, _skill);
} catch(const luabind::error &err) {
ScriptManager->HandleLuaError(err);
// Fall back to hard-coded mode
Expand Down Expand Up @@ -180,11 +182,11 @@ bool SkillAction::Execute()
bool SkillAction::Update()
{
// When there is no update function, the animation is done.
if(!_update_function.is_valid())
if(!_update_function->is_valid())
return true;

try {
return ScriptCallFunction<bool>(_update_function);
return ScriptCallFunction<bool>(*_update_function);
} catch(const luabind::error &err) {
ScriptManager->HandleLuaError(err);
return true;
Expand Down Expand Up @@ -266,14 +268,14 @@ bool ItemAction::Execute()
// Note that the battle item is already removed from the item list at that
// step.

const ScriptObject &script_function = _item->GetItem().GetBattleUseFunction();
ScriptObject *script_function = _item->GetItem().GetBattleUseFunction();
bool ret = false;
if(!script_function.is_valid()) {
if(!script_function || !script_function->is_valid()) {
IF_PRINT_WARNING(BATTLE_DEBUG) << "item did not have a battle use function" << std::endl;
}

try {
ret = ScriptCallFunction<bool>(script_function, _actor, _target);
ret = ScriptCallFunction<bool>(*script_function, _actor, _target);
} catch(const luabind::error &err) {
ScriptManager->HandleLuaError(err);
ret = false;
Expand Down
5 changes: 3 additions & 2 deletions src/modes/battle/battle_actions.h
Expand Up @@ -189,9 +189,10 @@ class SkillAction : public BattleAction

/** The functions of the possible attack animation skill.
*** When valid, the Update function should be called until the function returns true.
//! Do not delete them. Luabind's garbage collector will handle it.
**/
ScriptObject _init_function;
ScriptObject _update_function;
ScriptObject *_init_function;
ScriptObject *_update_function;

//! \brief Tells whether the battle action animation is scripted.
bool _is_scripted;
Expand Down

0 comments on commit a86034a

Please sign in to comment.