Adding Variables to Datablocks via source code
by Alex Scarborough · 01/30/2005 (1:06 am) · 7 comments
Open up ShapeBase.cc. Notice something? There are *two* datablock declarations. The first one
The addField command requires the following parameters.
in_pFieldname (string. This is the name of the datablock field in script.)
in_fieldType (This is the type of variable that will be stored. Filename, bool, int, float, ExplosionDataPtr, whatever).
in_fieldOffset (This is usually two part. Offset(Param1, Param2) where Param1 is the name of the source code variable, and Param2 is the name of the datablock)
in_FieldDoc (String. This is just a quick explanation of what the variable is used for that DOxygen will grab. Please use this if you're going to distribute your changes)
Those are just for a "simple" field, but in many cases, that is all you'll need.
Wait, backup, how exactly does this all work together?
Okay then, let's walk through adding a simple variable to ShapeBase that isn't changed during the course of a mission. We'll call our field "testField". First, open up shapeBase.h. Scroll down until you see the line
Here's where every static ShapeBaseData variable is initially declared. (dyanmic variables are declared under "class ShapeBase : public GameBase") Find a nice spot to add your variable, preferably in a place where it makes sense. For the purpose of this tutorial, let's say that testField is a bool representing some physical property. Therefore, below
add
Congrats, you're done with ShapeBase.h.
Now back in ShapeBase.cc Add a default value for your variable in ShapeBaseData::ShapeBaseData. for example, under
add
Next, go to initPersistFields, and under
add
Then, go into packData, and scroll down until you see
Under that, add
Finally, go to unpackData find
and add
Congrats!!! You've now added your own custom variable to ShapeBaseData that is accessible via script. However, this variable can only be set in the datablock declaration, you can't change it after mission load. Adding a variable that can be changed during the course of a missions is a very very similar process. Simply put the variable declaration in the ShapeBaseData() under Implement_CO_NETOBJECT_V1 and instead of writing to the stream in packData, write to it in packUpdate. Fairly simple concept once you get the hang of it, no?
Notes: This is a complete list of how to write thigns to the bit stream. If you're making a multiplayer game, memorize it.
It is *extremely* important that you write to and read from the bit stream in the same order with the same bit counts.
These instructions just used ShapeBase as an example. They will work with any other datablock.
It really isn't too hard to pick this up from other tutorials available, but I figured that having one whose purpose was to explain what is going on was a good idea.
IMPLEMENT_CO_DATABLOCK_V1(ShapeBaseData);establishes all static declarations of ShapeBaseData, such as the mass, drag, density, etc. All of these variables are sent to each client only once at mission load ("Loading Datablocks") in the packData function. Furthermore, the variables accessible via script are defined in initPersistFields via addField:
addField("shapeFile", TypeFilename, Offset(shapeName, ShapeBaseData)); The addField command requires the following parameters.
in_pFieldname (string. This is the name of the datablock field in script.)
in_fieldType (This is the type of variable that will be stored. Filename, bool, int, float, ExplosionDataPtr, whatever).
in_fieldOffset (This is usually two part. Offset(Param1, Param2) where Param1 is the name of the source code variable, and Param2 is the name of the datablock)
in_FieldDoc (String. This is just a quick explanation of what the variable is used for that DOxygen will grab. Please use this if you're going to distribute your changes)
Those are just for a "simple" field, but in many cases, that is all you'll need.
Wait, backup, how exactly does this all work together?
Okay then, let's walk through adding a simple variable to ShapeBase that isn't changed during the course of a mission. We'll call our field "testField". First, open up shapeBase.h. Scroll down until you see the line
struct ShapeBaseData : public GameBaseData { (Line 370) Here's where every static ShapeBaseData variable is initially declared. (dyanmic variables are declared under "class ShapeBase : public GameBase") Find a nice spot to add your variable, preferably in a place where it makes sense. For the purpose of this tutorial, let's say that testField is a bool representing some physical property. Therefore, below
F32 repairRate;
add
bool testField;
Congrats, you're done with ShapeBase.h.
Now back in ShapeBase.cc Add a default value for your variable in ShapeBaseData::ShapeBaseData. for example, under
repairRate = 0.0033;
add
testField = false;
Next, go to initPersistFields, and under
addGroup("Misc"); add
addField("testField", TypeBool, Offset(testField, ShapeBaseData));Then, go into packData, and scroll down until you see
stream->writeFlag(renderWhenDestroyed);
Under that, add
stream->writeFlag(testField);
Finally, go to unpackData find
renderWhenDestroyed = stream->readFlag();
and add
testField = stream->readFlag();
Congrats!!! You've now added your own custom variable to ShapeBaseData that is accessible via script. However, this variable can only be set in the datablock declaration, you can't change it after mission load. Adding a variable that can be changed during the course of a missions is a very very similar process. Simply put the variable declaration in the ShapeBaseData() under Implement_CO_NETOBJECT_V1 and instead of writing to the stream in packData, write to it in packUpdate. Fairly simple concept once you get the hang of it, no?
Notes: This is a complete list of how to write thigns to the bit stream. If you're making a multiplayer game, memorize it.
It is *extremely* important that you write to and read from the bit stream in the same order with the same bit counts.
These instructions just used ShapeBase as an example. They will work with any other datablock.
It really isn't too hard to pick this up from other tutorials available, but I figured that having one whose purpose was to explain what is going on was a good idea.
About the author
#2
01/30/2005 (2:55 pm)
Ya think? I thought I skipped over way too much that can be done with packUpdate and masks. Maybe for another resource...
#3
01/31/2005 (11:07 am)
@Alex: Yes, exploration and explanation of the various ways to properly compress and use masks would be great, but we see the general question a lot, and this is a great link to point folks to when they are getting started!
#4
to check it out for real. Rather than take your word for it.
????
06/12/2005 (2:17 pm)
I thought that was a bad code example. How about an ftp siteto check it out for real. Rather than take your word for it.
????
#5
06/12/2005 (3:50 pm)
Take my word for what now?
#6
07/31/2007 (6:01 pm)
This tutorial was exactly what i needed. Thanks alot man
#7
Currently I have the default set in Projectile::Projectile(). It is set as mNumBounces = 1;, any number I put in works but this is the only place I have managed to affect it.
Later on in bool Projectile::onAdd() I have mNumBounces = mDataBlock->numBounces;.
I thought that was what took the script from the weapons projectile datablock, am I using this in the right way?
Any help would be awesome, thanks.
09/25/2008 (4:13 pm)
Very helpful, you should write up a followup resource! Also, I am currently attempting to add bounce to my projectiles, I have it sort of working after ninjaing how bounce works on debris. However I am running into a problem, it uses the default number I set for numBounces in the code regardless of what number I put on the projectile datablock in the script.Currently I have the default set in Projectile::Projectile(). It is set as mNumBounces = 1;, any number I put in works but this is the only place I have managed to affect it.
Later on in bool Projectile::onAdd() I have mNumBounces = mDataBlock->numBounces;.
I thought that was what took the script from the weapons projectile datablock, am I using this in the right way?
Any help would be awesome, thanks.

Torque 3D Owner Stephen Zepp