Is this function evil or what? Hack alert or good solution?
by Demolishun · in Torque 3D Professional · 08/11/2013 (4:55 am) · 4 replies
I just dreamed up this function to solve an issue with adding a plugin to the editor system:
The usage for this function for me is to change the outcome of the isDirty function of my plugin depending upon where this is called. That way I don't have to modify the way the editor works when dealing with plugins. So my usage is like this:
The point is to keep the main dirty check from asking you to save even if the level has not changed. So it would return false during that check for isDirty. However, when I actually go to save to a file it uses the isDirty check to determine if the plugin should save. So I use the backtraceList function to return a backtrace array so I can determine if the function above the current one is the actual save function call. If it is then it returns true. So this function allows me to neatly force a save event on a plugin that really cannot return whether or not it is dirty because there is no such concept of being dirty/unsaved for the plugin.
// get backtrace array
DefineEngineFunction(backtraceList, int, ( ),,
"@brief returns an array of the scripting call stack.nn"
"Used to trace functions called from within functions. Can help discover what functions were called "
"(and not yet exited) before the current point in scripts. Last function called is first in list.nn"
"@ingroup Debugging")
{
U32 totalSize = 1;
for(U32 i = 0; i < gEvalState.getStackDepth(); i++)
{
if(gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage)
totalSize += dStrlen(gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage) + 2;
if(gEvalState.stack[i]->scopeName)
totalSize += dStrlen(gEvalState.stack[i]->scopeName) + 3;
if(gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mName)
totalSize += dStrlen(gEvalState.stack[i]->scopeNamespace->mName) + 2;
}
ArrayObject* arrList = new ArrayObject();
String buf;
for(U32 i = 0; i < gEvalState.getStackDepth(); i++)
{
buf = "";
if(gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage)
{
buf += "[";
buf += gEvalState.stack[i]->scopeNamespace->mEntryList->mPackage;
buf += "]";
}
if(gEvalState.stack[i]->scopeNamespace && gEvalState.stack[i]->scopeNamespace->mName)
{
buf += gEvalState.stack[i]->scopeNamespace->mName;
buf += "::";
}
if(gEvalState.stack[i]->scopeName)
buf += gEvalState.stack[i]->scopeName;
arrList->push_front(String::ToString(i), buf);
}
// make object live
arrList->registerObject();
// return object id for list
return arrList->getId();
}The usage for this function for me is to change the outcome of the isDirty function of my plugin depending upon where this is called. That way I don't have to modify the way the editor works when dealing with plugins. So my usage is like this:
function DatabaseSaveManagerPlugin::isDirty(%this)
{
%arr = backtraceList();
/*
for(%i = 0; %i < %arr.count(); %i++)
{
echo(%arr.getValue(%i));
}
*/
// only return true if called from EditorSaveMission
if(%arr.count() >= 2)
{
if(%arr.getValue(1) $= "EditorSaveMission")
return true;
}
return false;
}The point is to keep the main dirty check from asking you to save even if the level has not changed. So it would return false during that check for isDirty. However, when I actually go to save to a file it uses the isDirty check to determine if the plugin should save. So I use the backtraceList function to return a backtrace array so I can determine if the function above the current one is the actual save function call. If it is then it returns true. So this function allows me to neatly force a save event on a plugin that really cannot return whether or not it is dirty because there is no such concept of being dirty/unsaved for the plugin.
About the author
I love programming, I love programming things that go click, whirr, boom. For organized T3D Links visit: http://demolishun.com/?page_id=67
#2
Neither trace nor backtrace are designed to be used to make decisions in a program. backtracelist is designed for making decisions in code.
08/12/2013 (11:32 am)
I copied and modified backtrace to return an array I could use to programmatically make decisions in "code" based upon the functions that were called leading up to the called of backtraceList. Backtrace only prints to the console, it does not return anything in the default implementation.Neither trace nor backtrace are designed to be used to make decisions in a program. backtracelist is designed for making decisions in code.
#3
very much interesting.
never thought/imagine about that type decision.
can u give an example in which situation this type of decision needed ?
08/12/2013 (11:55 am)
"make decisions in "code" based upon the functions that were called "very much interesting.
never thought/imagine about that type decision.
can u give an example in which situation this type of decision needed ?
#4
I added a plugin to the T3D editor. One of the callbacks of a plugin for the T3D editor is "isDirty". This function is used in two places. One place is to determine if the level has changed. So every time you quit the world editor it checks the editors and editor plugins to find out if any settings/objects changed to see if a save is required to not lose those changes. The second time isDirty is used is when you do a save it checks the plugins to find out if they have data to save.
So, the reason I needed this is because I don't want it to pop up and say I need to save every time I leave the editor. But I need to be able to save the mission to a database any time the mission is saved. So the function isDirty needed to know from where it was being called. So getting a stack trace in script allows me to determine which function called the isDirty function and choose to return true or false based upon that function. That is what the second code block in the OP is showing. Sorry I did not make that more clear.
backtraceList could also be useful for other functions like AI think operations to determine context of the call. Of course there might be better ways to do this. At the very least it provides a programmable backtrace listing for debugging or even remote analysis. I guess it might be better to modify the existing backtrace command to provide this array as well, but I would also want an option to silence the print to console if used for general programming like the editor.
08/12/2013 (1:33 pm)
I did in the original post. I added a plugin to the T3D editor. One of the callbacks of a plugin for the T3D editor is "isDirty". This function is used in two places. One place is to determine if the level has changed. So every time you quit the world editor it checks the editors and editor plugins to find out if any settings/objects changed to see if a save is required to not lose those changes. The second time isDirty is used is when you do a save it checks the plugins to find out if they have data to save.
So, the reason I needed this is because I don't want it to pop up and say I need to save every time I leave the editor. But I need to be able to save the mission to a database any time the mission is saved. So the function isDirty needed to know from where it was being called. So getting a stack trace in script allows me to determine which function called the isDirty function and choose to return true or false based upon that function. That is what the second code block in the OP is showing. Sorry I did not make that more clear.
backtraceList could also be useful for other functions like AI think operations to determine context of the call. Of course there might be better ways to do this. At the very least it provides a programmable backtrace listing for debugging or even remote analysis. I guess it might be better to modify the existing backtrace command to provide this array as well, but I would also want an option to silence the print to console if used for general programming like the editor.
Ahsan Muzaheed
Default Studio Name
"
Entering ConsoleEntry::eval()
==>backtrace();
Leaving ConsoleEntry::eval() - return
"
to get a tree view i call "backtrace()" within my BackTrace:
">ConsoleEntry::eval->function."