Game Development Community

addfield() - persistent members

by Edward F. Maurina III · in Torque Game Engine · 04/06/2003 (12:06 am) · 5 replies

Hello all. I'm currently doing research on the vehicle class and associated code/classes. As part of this, I'm hooking up debug code to make my life easier while I work. I'm having a strange problem though. It goes like this.

I've added so members to Vehicle class and made them visible:

In vehicle.h
bool bVehicleDebugMode;

In vehicle.cc
void Vehicle::initPersistFields()
{
   Parent::initPersistFields();

   addField("disableMove",			TypeBool,		Offset(mDisableMove, Vehicle));
...
   addField("vehicleDebugMode",		TypeBool,		Offset(bVehicleDebugMode, Vehicle)); //EFM
...
}

and

void Vehicle::renderObject(SceneState* state, SceneRenderImage* image)
{
   Parent::renderObject(state, image);
   if (gShowBoundingBox || bVehicleDebugMode) { // NOT WORKING
...

At this point, the variable 'disableMove' shows up when I select my vehicle and examine it using the inspector. However, if I change the value and click apply, I see no change.

Thinking that 'maybe' the renderObject method does not always get called, I added this to the 'renderObject' method to see if it was being called:

nCount++;
	  if(nCount > 30) {
		  Con::warnf("Vehicle::renderObject mDisableMove:%d bVehicleDebugMode:%d myMassNode.x:%f mDataBlock->massCenter.x:%f",
			         mDisableMove, bVehicleDebugMode,  myMassNode.x, (mDataBlock->massCenter).x);
		  nCount=0;
	  }


Sure enough, it gets called every cycle. I sat for a bit...stumped. Then I experimented and mounted the vehicle. As soon as I did this, viola the update (from the prior apply) took effect.

Can anyone give me a clue here. I must be missing something. I can't figure out why my changes don't take effect immediately.

-Ed

#1
04/06/2003 (4:38 am)
I cant be exactly sure but I believe this is what is happening....

When you call a vehicle object from script, it is the server vehicle object that is updated. When this happens you have bVehicleDebugMode set to true on the server and set to false on the client. Obviously, only the client needs to render hence your if statement in renderObject is always failing.

What you need to do when you change the value of bVehicleDebugMode is to then tell the client/s that this value has changed. To do this you use setMaskBit() function. As this is not something that will be used ALL the time you should probably set up a new maskbit so as to not be constantly updating this data.

Step one.
Add a new maskbit into the vehicle.h vehicle declaration like so.
DebugMask = Parent::NextFreeMask << 2,
NextFreeMask = Parent::NextFreeMask << 3
also add a variable to store the last value of bVehicleDebugMode.
bool bLastDebugMode;

Step Two.
In a function that is run every tick...probably Vehicle::processTick, add the following. Basically, if there is a change in the status of bVehicleDebugMode we want to execute the packupdate.
if(isServerObject())
{
    if(bVehicleDebugMode != bLastDebugMode)
    {
        setMaskBits(DebugMask);
        bLastDebugMode = bVehicleDebugMode;
    }
}

Step Three.
In packupdate, before the energymask stuff insert the following.
This sends the infromation from the server to the client only when the DebugMask is set.
if (stream->writeFlag(mask & DebugMask))
   {
       stream->writeFlag(bVehicleDebugMode);
   }

and we need to do the similiar thign in the unpackupdate at the same postition

if (stream->readFlag()) {
   bVehicleDebugMode = stream->readFlag();
}

That should then fix your problem as now the client variable will update the same as the server and hence, will render properly.

Hope that helps
#2
04/06/2003 (9:30 am)
If sending nothing more than a boolean, it's not worth setting up a dirty mask as well. The mask flag is being sent every update, so might as well send the actual boolean instead of the mask flag. Just an optimization to Daniel's suggested fix.

Delayed updates are almost always the result of making a server-side change that doesn't cause the dirty mask to be set. Then a later server-side action, which could be unrelated to the earlier change, does set the dirty mask, and causes the earlier changes to be sent to the client.
#3
04/06/2003 (11:52 am)
Thanks to both of you Daniel and Brad for your replies. I'll review this data and give it a go. I beat my head against this bugger for several hours yesterday, knowing there was something I was missing.

BTW, I will be making changes to multiple parameters (experimenting with params on the fly), so I can afford to incur this overhead for now. Anyway, its all in the name of learning and debug. When I'm done I'll probably revert to the HEAD copy.

Thanks again,

Ed

PS - I've follwed the above instructions and it works like a charm. Thanks!
#4
04/06/2003 (5:00 pm)
Thats good to hear.

@Brad: Yeah, I realised that it is sending the mask bit anyway, as well as the debug value, which is actually more traffic but I wanted to explain how the system works to Edward. That is why I showed the whole of the bitmask process. :)
#5
03/13/2007 (5:22 pm)
Since bVehicleDebugMode is a static field, wouldn't it be better to use the ::onStaticModified callback rather than doing a polling loop in ::processTick?

Instead of...
void Vehicle::processTick(const Move *move)
{
    if(isServerObject())
    {
        if(bVehicleDebugMode != bLastDebugMode)
        {
            setMaskBits(DebugMask);
            bLastDebugMode = bVehicleDebugMode;
        }
    }
}
...maybe something like...
void Vehicle::onStaticModified(const char* slotName)
{
    if(strcmp(slotName,"VehicleDebugMode")==0)
        setMaskBits(DebugMask);
}
?