Permalink
Browse files

Turned the use of script object back to new allocated pointers.

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...
1 parent 1026991 commit a86034a28116ae97b2c892784c49c68195e0675d Yohann Ferreira committed Nov 2, 2012
@@ -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()) {
@@ -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
//@{
@@ -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.
**/
@@ -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;
@@ -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")) {
@@ -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;
@@ -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
@@ -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;
@@ -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;
@@ -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);
@@ -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
@@ -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()
@@ -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)
@@ -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
@@ -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
@@ -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;
@@ -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;
@@ -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;
Oops, something went wrong.

0 comments on commit a86034a

Please sign in to comment.