Client-side only sceneobject from script
by Lukas Joergensen · in Torque 3D Professional · 07/30/2013 (2:48 pm) · 12 replies
Hey guys!
I spawn a bunch of PointLights as described in this thread.
The PointLights is spawned in the "AddParticle" call in the emitter which is called from the advanceTime callback which should only be called client-side. So the PointLights are spawned client-side.
However when the PointLights are about to get updated later on, for some reason they have become server-side object. The reason this can happen is because the server is local. But why it happens and how to prevent it is unknown to me.
Does anybody know how I can spawn the PointLights as client-side objects only?
Right now I tried setting the mNetFlags to isGhost but it didn't help.
Any ideas?
I spawn a bunch of PointLights as described in this thread.
The PointLights is spawned in the "AddParticle" call in the emitter which is called from the advanceTime callback which should only be called client-side. So the PointLights are spawned client-side.
However when the PointLights are about to get updated later on, for some reason they have become server-side object. The reason this can happen is because the server is local. But why it happens and how to prevent it is unknown to me.
Does anybody know how I can spawn the PointLights as client-side objects only?
Right now I tried setting the mNetFlags to isGhost but it didn't help.
Any ideas?
About the author
IPS Bundle available at: https://www.winterleafentertainment.com/Products/IPS.aspx
#2
Anw do the mNetFlags have to be set in the constructor? My initializeParticle function currently looks like this:
Thats is when obj->setGhost(); is called which looks like this:
07/30/2013 (4:36 pm)
@Azaezel If you have 200 lights flying around, you'd prefer not to have to send all those 200 lights over the connection but instead just sending a ParticleEmitter to emit those lights.Anw do the mNetFlags have to be set in the constructor? My initializeParticle function currently looks like this:
void SceneObjectParticleManager::initializeParticle(Particle* init, const Point3F& inheritVelocity, ParticleData* pDat)
{
ParticleManager::initializeParticle(init, inheritVelocity, pDat);
SceneObjectParticle* _init = static_cast<SceneObjectParticle*>(init);
SceneObjectParticleData* _pDat = static_cast<SceneObjectParticleData*>(pDat);
// assign spin amount
S32 objID = _pDat->CreateSceneObject_callback();
SceneObject* obj;
if(!Sim::findObject(objID, obj))
_init->object = NULL;
else
_init->object = obj;
obj->setGhost();
obj->setSelectionEnabled(false);
_init->setPosition(_init->pos);
}Setting the mNetFlags after the construction of the light. Thats is when obj->setGhost(); is called which looks like this:
void setGhost() { mNetFlags = IsGhost | ScopeLocal; };
#3
Might be able to set it immediately after object-instance creation... Where's that?
07/30/2013 (4:57 pm)
The LightBase constructor sets it, so used the PointLight constructor as an example in order to override that functionality. Might be able to set it immediately after object-instance creation... Where's that?
#4
I really really would like clients to be able to construct the objects from script (since I want a general solution for all SceneObjects).
But perhaps that is not possible?
07/30/2013 (5:02 pm)
This line:S32 objID = _pDat->CreateSceneObject_callback();Makes a call to this script function:
function DefaultSceneObjectParticleData::CreateSceneObject()
{
%light = new PointLight()
{
color = getRandom(55, 200) SPC getRandom(55, 200) SPC getRandom(55, 200);
brightness = 0.7;
flareScale = 0.3;
flareType = LightFlareExample2;
};
return %light;
}Which is where the object is created. However I don't know how much the script-side stuff does.I really really would like clients to be able to construct the objects from script (since I want a general solution for all SceneObjects).
But perhaps that is not possible?
#5
07/30/2013 (5:02 pm)
I am not sure if there is really a difference for a combo client/server. Does it behave properly on a separated client and server?
#6
@Lukas: not entirely sure what all lies between scripted new calls and
void NetConnection::objectInScope(NetObject *obj)
just yet, but it's certainly an interesting query, at least.
07/30/2013 (5:25 pm)
@demolishun: That imgur link shows it having seperate results when forced to do so right off the bat. (Left is connected client, Right is client/server 'connected' to it's self.)@Lukas: not entirely sure what all lies between scripted new calls and
void NetConnection::objectInScope(NetObject *obj)
just yet, but it's certainly an interesting query, at least.
#7
mNetFlags.clear(Ghostable);
mNetFlags.set(IsGhost);
07/30/2013 (7:35 pm)
This should make it entirely client side. A little trick i learned from the RTS starter kit way back. Still seems to work in T3D and has come in handy for a few things. There are always things that are just for display the server just does not need to worry about.mNetFlags.clear(Ghostable);
mNetFlags.set(IsGhost);
#8
Where a client only machine would see the object, but the server would not.
Can T3D running as both client and server really separate the two?
07/30/2013 (7:46 pm)
What I meant was an object created on T3D running as both client and server would still be available to the server. I am just not sure what it would do about ghosting.Where a client only machine would see the object, but the server would not.
Can T3D running as both client and server really separate the two?
#9
07/30/2013 (8:08 pm)
Lukas: I'm pretty sure calling new from TorqueScript results in more than the constructor being called - i.e. registerObject and so on. It could be that that code is doing networking stuff.
#10
07/30/2013 (10:59 pm)
There are client-side only datablocks for use with decals - so it must be possible.
#11
07/31/2013 (4:36 am)
Okay this is what I do currently:PointLight* obj = new PointLight();
ColorI color = ColorI(gRandGen.randI(55, 200), gRandGen.randI(55, 200), gRandGen.randI(55, 200));
obj->setDataField(StringTable->insert("color"), 0,
avar("%f %f %f %f", color.red, color.green, color.blue, color.alpha));
obj->setDataField(StringTable->insert("brightness"), 0,
"0.7");
obj->setDataField(StringTable->insert("flareScale"), 0,
"0.3");
obj->setDataField(StringTable->insert("flareType"), 0,
"LightFlareExample2");
obj->setGhost();
obj->setSelectionEnabled(true);
if(!obj->registerObject())
delete obj;
else
_init->object = obj;
_init->setPosition(_init->pos);And it seems to fix the client-side stuff issue, however those lights aren't working anymore for some reason. They show up in the editor as small light bulbs flying around, but prepRenderImage isn't called and the ground is not lit up where the lights are. Any clues? Is there another step needed in the initialization of the lights?
#12
Too bad this means that I can't create a general class for all SceneObject but have to create a "PointLightParticleManager", a "ShapeParticleManager" etc.
Thanks tho anyways guys! I can continue my work now ;)
07/31/2013 (10:08 am)
Okay the issue was that I had to conform the light manually when I updated the position of the lights (previously this was done by unpackUpdate) and I had to use ColorF instead of ColorI for the colours.Too bad this means that I can't create a general class for all SceneObject but have to create a "PointLightParticleManager", a "ShapeParticleManager" etc.
Thanks tho anyways guys! I can continue my work now ;)
Azaezel
Really don't see why you'd want to, but try:
PointLight::PointLight() : mRadius( 5.0f ) { // We set the type here to ensure the extended // parameter validation works when setting fields. mLight->setType( LightInfo::Point ); mNetFlags.set( ScopeLocal); }