Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit a86034a28116ae97b2c892784c49c68195e0675d 1 parent 1026991
Yohann Ferreira authored
View
6 src/common/global/global_objects.cpp
@@ -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()) {
View
30 src/common/global/global_objects.h
@@ -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;
View
10 src/common/global/global_skills.cpp
@@ -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;
View
30 src/common/global/global_skills.h
@@ -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,9 +123,8 @@ 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);
@@ -135,9 +132,8 @@ class GlobalSkill
/** \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;
View
4 src/engine/script/script_read.h
@@ -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);
View
49 src/engine/script_supervisor.cpp
@@ -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,7 +96,7 @@ 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]);
}
@@ -81,20 +104,20 @@ 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)
View
15 src/engine/script_supervisor.h
@@ -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
View
20 src/modes/battle/battle_actions.cpp
@@ -92,15 +92,17 @@ 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();
}
@@ -108,7 +110,7 @@ SkillAction::SkillAction(BattleActor *actor, BattleTarget target, GlobalSkill *s
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;
View
5 src/modes/battle/battle_actions.h
@@ -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;
View
24 src/modes/map/map.cpp
@@ -216,8 +216,8 @@ void MapMode::Update()
_dialogue_icon.Update();
// Call the map script's update function
- if(_update_function.is_valid())
- ScriptCallFunction<void>(_update_function);
+ if(_update_function->is_valid())
+ ScriptCallFunction<void>(*_update_function);
// Update all animated tile images
_tile_supervisor->Update();
@@ -263,8 +263,8 @@ void MapMode::Draw()
VideoManager->SetCoordSys(0.0f, SCREEN_GRID_X_LENGTH, SCREEN_GRID_Y_LENGTH, 0.0f);
VideoManager->SetDrawFlags(VIDEO_X_CENTER, VIDEO_Y_BOTTOM, 0);
- if(_draw_function.is_valid())
- ScriptCallFunction<void>(_draw_function);
+ if(_draw_function->is_valid())
+ ScriptCallFunction<void>(*_draw_function);
else
_DrawMapLayers();
@@ -547,13 +547,15 @@ bool MapMode::_Load()
}
// Call the map script's custom load function and get a reference to all other script function pointers
- ScriptObject map_table(luabind::from_stack(_map_script.GetLuaState(), hoa_script::private_script::STACK_TOP));
- ScriptObject function = map_table["Load"];
+ // We use a newly allocated pointer to avoid a memory corruption due to luabind's garbage collector.
+ ScriptObject *map_table = new ScriptObject(luabind::from_stack(_map_script.GetLuaState(), hoa_script::private_script::STACK_TOP));
+ ScriptObject *function = new ScriptObject();
+ *function = (*map_table)["Load"];
bool loading_succeeded = true;
- if(function.is_valid()) {
+ if(function->is_valid()) {
try {
- ScriptCallFunction<void>(function, this);
+ ScriptCallFunction<void>(*function, this);
} catch(const luabind::error &e) {
ScriptManager->HandleLuaError(e);
loading_succeeded = false;
@@ -573,8 +575,10 @@ bool MapMode::_Load()
return false;
}
- _update_function = _map_script.ReadFunctionPointer("Update");
- _draw_function = _map_script.ReadFunctionPointer("Draw");
+ _update_function = new ScriptObject();
+ *_update_function = _map_script.ReadFunctionPointer("Update");
+ _draw_function = new ScriptObject();
+ *_draw_function = _map_script.ReadFunctionPointer("Draw");
// ---------- (6) Prepare all sprites with dialogue
// This is done at this stage because the map script's load function creates the sprite and dialogue objects. Only after
View
6 src/modes/map/map.h
@@ -317,14 +317,16 @@ class MapMode : public hoa_mode_manager::GameMode
*** This function implements any custom update code that the specific map needs to be performed.
*** The most common operation that this script function performs is to check for trigger conditions
*** that cause map events to occur
+ *** Do not delete it. Luabind's garbage collector will handle it.
**/
- ScriptObject _update_function;
+ ScriptObject *_update_function;
/** \brief Script function which assists with the MapMode#Draw method
*** This function allows for drawing of custom map visuals. Usually this includes lighting or
*** other visual effects for the map environment.
+ *** Do not delete it. Luabind's garbage collector will handle it.
**/
- ScriptObject _draw_function;
+ ScriptObject *_draw_function;
// ----- Members : Properties and State -----
View
8 src/modes/map/map_objects.cpp
@@ -1471,16 +1471,18 @@ void ObjectSupervisor::ReloadVisiblePartyMember()
if(actor && actor->GetMapSpriteName() != _visible_party_member->GetSpriteName()) {
hoa_script::ReadScriptDescriptor &script = GlobalManager->GetMapSpriteScript();
- ScriptObject function_ptr = script.ReadFunctionPointer("ReloadSprite");
+ // Do not delete that pointer, it will be handled by luabind's garbage collector.
+ ScriptObject *function_ptr = new ScriptObject();
+ *function_ptr = script.ReadFunctionPointer("ReloadSprite");
- if(!function_ptr.is_valid()) {
+ if(!function_ptr->is_valid()) {
PRINT_WARNING << "Invalid 'ReloadSprite' function in the map sprite script file."
<< std::endl;
return;
}
try {
- ScriptCallFunction<void>(function_ptr, _visible_party_member, actor->GetMapSpriteName());
+ ScriptCallFunction<void>(*function_ptr, _visible_party_member, actor->GetMapSpriteName());
} catch(const luabind::error &e) {
PRINT_ERROR << "Error while loading script function." << std::endl;
ScriptManager->HandleLuaError(e);
View
14 src/modes/menu/menu_views.cpp
@@ -348,15 +348,15 @@ void InventoryWindow::Update()
// Returns an item object, already removed from inventory.
// Don't forget to readd the item if not used, or to delete the pointer.
GlobalItem *item = (GlobalItem *)GlobalManager->RetrieveFromInventory(obj->GetID());
- const ScriptObject &script_function = item->GetFieldUseFunction();
- if(!script_function.is_valid()) {
+ ScriptObject *script_function = item->GetFieldUseFunction();
+ if(!script_function || !script_function->is_valid()) {
IF_PRINT_WARNING(MENU_DEBUG) << "item did not have a menu use function" << std::endl;
} else {
if(IsTargetParty(item->GetTargetType()) == true) {
GlobalParty *ch_party = GlobalManager->GetActiveParty();
// If the item use failed, we readd it to inventory.
- if(!ScriptCallFunction<bool>(script_function, ch_party))
+ if(!ScriptCallFunction<bool>(*script_function, ch_party))
GlobalManager->AddToInventory(item);
else // delete the item instance when succeeded.
delete item;
@@ -365,7 +365,7 @@ void InventoryWindow::Update()
GlobalCharacter *ch = dynamic_cast<GlobalCharacter *>(GlobalManager->GetActiveParty()->GetActorAtIndex(_char_select.GetSelection()));
// If the item use failed, we readd it to inventory.
- if(!ScriptCallFunction<bool>(script_function, ch))
+ if(!ScriptCallFunction<bool>(*script_function, ch))
GlobalManager->AddToInventory(item);
else // delete the item instance when succeeded.
delete item;
@@ -774,9 +774,9 @@ void SkillsWindow::Update()
GlobalCharacter *target = dynamic_cast<GlobalCharacter *>(GlobalManager->GetActiveParty()->GetActorAtIndex(_char_select.GetSelection()));
GlobalCharacter *instigator = dynamic_cast<GlobalCharacter *>(GlobalManager->GetActiveParty()->GetActorAtIndex(_char_skillset));
- const ScriptObject &script_function = skill->GetFieldExecuteFunction();
+ ScriptObject *script_function = skill->GetFieldExecuteFunction();
- if(!script_function.is_valid()) {
+ if(!script_function || !script_function->is_valid()) {
IF_PRINT_WARNING(MENU_DEBUG) << "selected skill may not be executed in menus" << std::endl;
break;
}
@@ -784,7 +784,7 @@ void SkillsWindow::Update()
IF_PRINT_WARNING(MENU_DEBUG) << "did not have enough skill points to execute skill " << std::endl;
break;
}
- ScriptCallFunction<void>(script_function, target, instigator);
+ ScriptCallFunction<void>(*script_function, target, instigator);
instigator->SubtractSkillPoints(skill->GetSPRequired());
MenuMode::CurrentInstance()->_menu_sounds["confirm"].Play();
} else if(event == VIDEO_OPTION_CANCEL) {
Please sign in to comment.
Something went wrong with that request. Please try again.