List Datablocks by Type
by Michael Perry · 06/12/2007 (12:19 pm) · 12 comments
While developing two in house tools for Zombie Shortbus (AFX Creator and Weaponcrafter), I discovered I needed a list of datablocks specified by their type. For instance, I wanted to fill a GuiListCtrl with the names of all "ParticleEmitterData" datablocks loaded during game play.
With these functions, I have can now implement tool features such as picking an existing datablock out of list, displaying it's attributes in a new GUI, modifying the attributes, and saving out the new datablock (plus re-executing), without ever opening up a script file.
I'm sure there are other applications that you might discover. The first code section is the actual engine change you need to make. The second code section is a script example for using the new function, getSpecificDatablocks().
Enjoy, and let me know if you have any suggestions for improvement or find bugs.
Add the following to the bottom of engine\console\consoleFunctions.cc:
Script implementation, written in server\scripts\game.cs:
With these functions, I have can now implement tool features such as picking an existing datablock out of list, displaying it's attributes in a new GUI, modifying the attributes, and saving out the new datablock (plus re-executing), without ever opening up a script file.
I'm sure there are other applications that you might discover. The first code section is the actual engine change you need to make. The second code section is a script example for using the new function, getSpecificDatablocks().
Enjoy, and let me know if you have any suggestions for improvement or find bugs.
Add the following to the bottom of engine\console\consoleFunctions.cc:
static const char* findNamespace(SimDataBlock * datablock, const char* searchValue)
{
// Grab the namespace
Namespace* pTemp = datablock->getNamespace();
// Traverse the family tree looking for our
// long lost parent
while(pTemp->mParent)
{
// Compare our names...are you my Mommy?
if(!dStrcmp(searchValue, pTemp->mName))
{
// We have found the parent we are looking for, get their name
return pTemp->mName;
}
// This isn't the parent you are looking for, go higher in the tree
pTemp = pTemp->mParent;
}
// We didn't find the parent, return 0 (poor, orphaned datablock (= )
return 0;
}
ConsoleFunction(getSpecificDatablocks, const char*, 2, 2, "getSpecificDatablocks(typeMask); get all datablocks of \"typeMask\" in string list format")
{
U32 iBufferSize = 0;
Vector<const char*> myVec;
// Get the typemaks we are searching for
const char* searchType = argv[1];
// Get all of our datablocks into one variable, a datablock group
SimDataBlockGroup * grp = Sim::getDataBlockGroup();
// Traverse the datablock group
for(SimDataBlockGroup::iterator i = grp->begin(); i != grp->end(); i++)
{
// Grab our current iterator's datablock
SimDataBlock * datablock = dynamic_cast<SimDataBlock*>(*i);
// Skip non-datablocks if we somehow encounter them.
if(!datablock)
continue;
// Get datablock name for matching
const char* name = findNamespace(datablock, searchType);
// Safety check, just in case
if(!name)
continue;
// Match datablock types
if(!dStrcmp(searchType, name))
{
// Keep track of our overall memory we are going
// to allocate for our return buffer
iBufferSize += dStrlen(datablock->getName())+ 1;
// Push the string back
myVec.push_back(datablock->getName());
}
}
// Create a return buffer (string format)
char* retBuffer = Con::getReturnBuffer(iBufferSize);
// Clear out the return buffer (paranoia check)
dStrcpy(retBuffer, "");
// Iterate our vector and fill up our returnBuffer
for(int i = 0; i < myVec.size(); i++)
{
dStrcat(retBuffer, myVec[i]);
dStrcat(retBuffer," ");
}
// Return
return retBuffer;
}Script implementation, written in server\scripts\game.cs:
[b]// Try passing in "PlayerData", "AudioProfile", and others[/b]
function getDatablocks(%name)
{
[b] // Get the list of datablocks[/b]
%list = getSpecificDatablocks(%name);
[b] // How many did we find?[/b]
%count = getWordCount(%list);
echo("Number of " @ %name @ " datablocks: " @ %count);
[b] // Loop through the list, grab each datablock, and print it out to the console[/b]
for(%i = 0; %i < %count; %i++)
{
%name = getWord(%list, %i);
echo(%name);
}
}About the author
Associate Producer / Project Manager for GarageGames
#2
getDatablocks("AudioProfile"); echoed out all the AudioProfiles for me
06/13/2007 (10:49 am)
Hmm, worked for me Joe.getDatablocks("AudioProfile"); echoed out all the AudioProfiles for me
#3
06/13/2007 (1:05 pm)
I put the code into tools/main.cs so that I could use this in the editor. What I'm trying for is inside a behavior, to fill an enum so I can select an AudioProfile for the object to use. I exec() my datablock scripts beforehand, but maybe it's not working because of some timing issue with behaviors (which seems to happen a lot).
#4
Are other datablocks showing up for you? If so, I think I can walk you through the debug steps to find out why certain ones aren't showing up...
06/13/2007 (1:10 pm)
Hmmm. I can't really test or debug this since I don't own TGB Pro....Are other datablocks showing up for you? If so, I think I can walk you through the debug steps to find out why certain ones aren't showing up...
#5
We were planning on implementing something similar but to additionally dump a list of all the datablocks which not only exist but have also actually been used. The idea being to cull out DBs which aren't actually in use and get a slight speed-up in connection times.
06/15/2007 (6:17 am)
Sounds like a very useful resource.We were planning on implementing something similar but to additionally dump a list of all the datablocks which not only exist but have also actually been used. The idea being to cull out DBs which aren't actually in use and get a slight speed-up in connection times.
#6
I know a big request of developers is the functionality of culling datablocks and objects to only what is needed, for the mission being loaded. I'm hoping this function helps my team, and others, get to that point.
Btw. I've found myself using this function for a lot of debugging lately. I've been writing some custom classes that have been failing to register, and the first thing I immediately check is if the datablocks are actually loaded in the game. Saved me a lot of time.
06/15/2007 (6:25 am)
That is exactly what we were hoping to get to as well, Orion =).I know a big request of developers is the functionality of culling datablocks and objects to only what is needed, for the mission being loaded. I'm hoping this function helps my team, and others, get to that point.
Btw. I've found myself using this function for a lot of debugging lately. I've been writing some custom classes that have been failing to register, and the first thing I immediately check is if the datablocks are actually loaded in the game. Saved me a lot of time.
#7
06/15/2007 (6:40 am)
hah, nice!
#8
My current use is for a remote client to display a list of available object types to select from. This is adequate for the server side to obtain the list of datablocks of a particular type, but other techniques will need to be used for getting a display list describing those datablocks from the server to the client's GUI.
10/08/2007 (3:38 pm)
This fills a need for me and was something I was looking for, thanks. However I think it is useful to point out one thing. As designed I believe it only works on the Server for server defined datablocks. (Many of the usage examples above were server only editor applications.) My current use is for a remote client to display a list of available object types to select from. This is adequate for the server side to obtain the list of datablocks of a particular type, but other techniques will need to be used for getting a display list describing those datablocks from the server to the client's GUI.
#9
@Matthew - Interesting observation. I'm barely awake right now, but I feel this will work from a client. I'll give it a spin now.
10/09/2007 (6:18 am)
Ohhhh k... My response was eaten.@Matthew - Interesting observation. I'm barely awake right now, but I feel this will work from a client. I'll give it a spin now.
#10
10/09/2007 (6:33 am)
Ok. So I just put the sample script function getDatablocks() in a client script. I did not host a server. I passed "playerData" into the function, and received the data I needed.
#11
10/09/2007 (8:14 am)
You're right, I was too restrictive. ;( I should have said something more like: it isn't intended to work on remote clients for datablocks defined on the server.
#12
You mentioned in your first post that mods would have to be made to grab the list of datablocks from the server to the client's GUI. Have you attempted this yet?
10/09/2007 (9:08 am)
Hmmm....welllll...there was no intention other than grabbing all the loaded datablocks regardless if you are the client or server.You mentioned in your first post that mods would have to be made to grab the list of datablocks from the server to the client's GUI. Have you attempted this yet?
Torque Owner Joe Rossi
Indri Games
Edit: It doesn't seem to be finding the AudioProfile datablocks for me, but hopefully it's possible.