Game Development Community

Delay NetEvent untill object has been ghosted

by Lukas Joergensen · in Torque 3D Professional · 01/04/2014 (5:02 am) · 8 replies

Hey guys, I have an issue where the following code fails:
%bhv1 = new AttractionBehaviour(){
      attractionrange = 10;
      Attraction_offset[0] = "0 0.3 1.5";
      Amount[0] = 2;
      AttractionMode[0] = Attract;
      attractedObjectID[0] = %spell.getSource();
   };
   %spell.baseEmitter = new ParticleEmitterNode(){
      dataBlock = DefaultEmitterNodeData;
      emitter = FireballChannelEmitterBASE;
      position = %spell.getSource().position;
   };
   %spell.baseEmitter.addParticleBehaviour(%bhv1, false);
Because the "addParticleBehaviour" NetEvent is being networked before the ParticleEmitterNode is ghosted.
So far I've solved this by scheduling it:
%spell.baseEmitter.schedule(32, "addParticleBehaviour", %bhv1, false);
However it is not very elegant, is there a way to make sure that the NetEvent is called after the object has been ghosted? Kindda like "ProcessAfter" on SceneObjects.

Or do you have another idea of how to deal with this issue?

#1
01/04/2014 (8:20 am)
Sorry it's a little vague, but I thought there was a callback when an object is ghosted. I know that there is a way to ask the server if an object is currently ghosted but again I don't remember the details.
#2
01/04/2014 (10:17 am)
Surely there's already a way to handle that synchronously else you would think that would be a problem of spawning projectiles (among other objects) and adding said object to MissionCleanup SimGroup that is used all over the place in TorqueScript.
#3
01/04/2014 (12:39 pm)
I didn't think of the 'processAfter' function call(for some reason?) but what I've been doing on the behaviors is handled engine side

Behavior instances require 2 dependencies: The template and the Owner. Both are ghosted down with the behaviors.

Because of the weird ordering shenanigans of the netcode, you can't reliably count on what gets ghosted first, so I had to make instances wait until the other stuff was sent over, which looks like this:

PackUpdate:
if ( mask & InitialUpdateMask )
{
	S32 tmpltGhostID = con->getGhostIndex(mTemplate);
	S32 ownerGhostID = con->getGhostIndex(mBehaviorOwner);

	if(tmpltGhostID != -1 && ownerGhostID != -1)
	{
		stream->writeFlag( true );
		stream->writeInt(tmpltGhostID, NetConnection::GhostIdBitSize);
		stream->writeInt(ownerGhostID, NetConnection::GhostIdBitSize);
	}
	else 
	{
		retmask |= InitialUpdateMask;
		stream->writeFlag( false );
	}
}
else
	stream->writeFlag( false );

UnPackUpdate:
if(stream->readFlag())
{
	S32 gIndex = stream->readInt( NetConnection::GhostIdBitSize );
        mTemplate = dynamic_cast<BehaviorTemplate*>( con->resolveGhost( gIndex ) );

	gIndex = stream->readInt( NetConnection::GhostIdBitSize );
        mBehaviorOwner = dynamic_cast<BehaviorComponent*>( con->resolveGhost( gIndex ) );
}

So what happens is we check that the ghost is valid for both the template and the owner entity. If one or neither is valid, we re-set the mask so we check again next update. This goes until conditions are met and we're happy.

I'll look a "callAfterGhost()" function or something as that could be useful for some stuff the behavior system is making use of as well as the situation you've got going there.

So yeah, I don't think there's a pure script solution at the moment, but you could rig a callback into script, or just do the event directly, when the above code successfully checks out that the emitter has been ghosted.
#4
01/04/2014 (10:50 pm)
Did you try sending the netevent in the pack? with a schedule say of a few milleseconds.

I dunno, I had to do something similar in OneWorld and if I remember right I slide a schedule event into the pack. so after it would pack the data it would schedule a system event to send the netevent in a second or so.

You could also do it differently :)

It would require highjacking in the netGhost.cpp file, but you could put a list of the behaviors on the object, and then before the pack is called around line 491 have it send the net events in the list.

I'd have to research it more, but thats where I would start looking to hijack if I were trying to do it.

vince
#5
01/04/2014 (10:51 pm)
Or... you could have your object signal an event that it was ghosted...

Just an idea.
#6
01/04/2014 (11:44 pm)
Thanks for all the suggestions guys!

@Jeff what I ended up doing was something similar to what you did, except I didn't do a check for anything. I just placed the "postNetEvent" code in the ParticleEmitterNode::packUpdate, after the SetEmitterDatablock flag, then it will be ghosted at the time the NetEvent arrives.

I would prefer being able to do this from a function outside the object tho, like "gc->postNetEventWhenGhost(evt, objectToWaitOn);"
#7
01/05/2014 (8:01 am)
EventManager could handle that....
#8
01/05/2014 (8:07 am)
@Richard, I've never worked with the EventManager, could you tell me how an EventManager solution would look?