Game Development Community

dev|Pro Game Development Curriculum

Client side TSStatic object

by Thomas \"Man of Ice\" Lund · 09/30/2004 (11:45 am) · 44 comments

Download Code File

What is this
With this code you can create 3d ingame objects that only exist in the scene of the client owning them. They do not exist on the server or other clients, and thus there is absolutely no overhead on the network when using these.

These objects are perfect for creating rich GUI's like waypoints, 3d reticles and other interfaces that you would otherwise have to do in 2d.

How to add
Simply unzip the files in the zip and dump into your game dir. Recompile. As simple as that

How to use
You can use this object from e.g. a GUI control. This example snippit below shows how to create the object on the client side. Remember to set a position.

ClientSideTSStatic* pWaypointMarker = new ClientSideTSStatic();
pWaypointMarker ->setField("shapeName", "game/data/shapes/waypoint.dts");
// Register the Object.
if (!pWaypointMarker ->registerObject())
{
   Con::errorf("Could not create waypoint marker");
   delete pWaypointMarker ;
}

There is no script interface. I'll leave that as an exercise to the reader ;-)

A special thanks to Ben for help on this resource.
Page «Previous 1 2 3 Last »
#1
09/30/2004 (12:44 pm)
Cool. I could use this for my commander map or a vehicle station.
#2
10/04/2004 (9:49 am)
I love the idea of the rich GUIs. Great idea.

-Ed
#3
10/05/2004 (5:08 am)
Just as a general inquiry... How would one implement one of these so-called "rich GUIs"? For example, I would like to have the number of rounds and clips displayed in the weapon the player is currently using, sort of like Halo. Any ideas on how something like this could be done?

-Barzahd
#4
12/10/2004 (4:57 pm)
Thomas, Thanks for this resource! I needed this resource for client side only TSStatic objects. I did not use them as GUI, I actually used this resource to place Trees, etc in the world without any other client or the server knowing.

I am not proficient in C++ so I had Robert Brower implement this resource and modify it to have an interface for scripted object placement. Here are the modifications Robert created for me:

Add this to the clientSideTSStatic.cc file:

// 12-08-2004 RFB -> console method to add shapes. can be called from client side script

ConsoleFunction( addClientSideTSStatic, S32, 5, 5, "(string shapeName, string position, string rotation, string scale)")

{
    ClientSideTSStatic* pCSStatic = new ClientSideTSStatic();
    pCSStatic->setField("shapeName", argv[1]);
    pCSStatic->setField("position", argv[2]);
    pCSStatic->setField("rotation", argv[3]);
    pCSStatic->setField("scale", argv[4]);
    // register the object
    if (!pCSStatic->registerObject())
    {
        Con::errorf("Could not register a ClientSideTSStatic");
        delete pCSStatic;
        return false;
    }
    return true;
}

// <- 12-08-2004 RFB

Here is the call to use in Script:

addClientSideTSStatic(%dtsincludingpath, %position, %rotation, %scale);

Good luck and enjoy this addition to the resource. Thanks Robert for helping me out with this!
#5
12/10/2004 (5:01 pm)
I hope she works! Good luck!
#6
12/11/2004 (1:11 am)
Verrrrryyyy cool :-)
#7
02/05/2005 (10:28 pm)
I have added this resource and I can add TSStatic objects with a script command, but when I do the objects have no handle in the world editor. Could anyone give me an idea why that is?

Thanks
#8
08/15/2005 (10:44 pm)
Thanks to everyone who posted on this topic so far! I played with the code Funkypeople posted and was able to make a a clientside object manager that can be accesed through the console. As Brandon noted, none of the client side objects are accesible from the world editor for reasons unknown to me.

Also, the collisions of those realtime spawned clientside objects are not working properly.. Anyone knows how to fix this?
#9
03/12/2006 (10:03 pm)
I think I am right among those on the loyal wait for the response~
#10
03/13/2006 (1:19 am)
The objects dont show up in the world editor, because they do not exist on the server side. There is no object id, replication to the clients etc.etc. - and thats what the editor manipulates.

Thats should also explain collisions and all the other things that "normally" work with regular objects. These things are calculated server side, and thats not happening with client side only objects.

So you can use these to offload work on the server, create 3d GUI elements and e.g.

They are _not_ regular objects

:-)
#11
04/13/2006 (5:32 am)
Anyone got this one to work under 1.4? My code seem to crash once it reaches
ClientSideTSStatic* pCSStatic = new ClientSideTSStatic();
#12
05/11/2006 (9:35 pm)
In order to work in 1.4 you should change following code:
function OnAdd
bool ClientSideTSStatic::onAdd()
{
   // Skip TSStatic onAdd
   if(!SceneObject::onAdd())
      return false;

   if (!mShapeName || mShapeName[0] == '[[60c21c82c86cf]]') 
   {
      Con::errorf("TSStatic::onAdd: no shape name!");
      return false;
   }
   mShapeHash = _StringTable::hashString(mShapeName);

   mShape = ResourceManager->load(mShapeName);

   if (bool(mShape) == false) 
   {
      Con::errorf("TSStatic::onAdd: unable to load shape: %s", mShapeName);
      return false;
   }

/*   if(isClientObject() && !mShape->preloadMaterialList() && NetConnection::filesWereDownloaded())
      return false; */

   mObjBox = mShape->bounds;
   resetWorldBox();
   setRenderTransform(mObjToWorld);

   mShapeInstance = new TSShapeInstance(mShape, true);

   // Scan out the collision hulls...
   //=== Tuan remove 12.5
  /* U32 i;
   for (i = 0; i < 8; i++) 
   {
      char buff[128];
      dSprintf(buff, sizeof(buff), "Collision-%d", i + 1);
      mCollisionDetails[i] = mShape->findDetail(buff);
      mLOSDetails[i]       = mCollisionDetails[i];
   }
   
// Compute the hull accelerators (actually, just force the shape to compute them)
   for (i = 0; i < 8; i++) 
   {
      if (mCollisionDetails[i] != -1) {
         mShapeInstance->getShape()->getAccelerator(mCollisionDetails[i]);
      }
   }
  //End remove
   */
   //=== Tuan add 12.5
   U32 i;
   for (i = 0; i < mShape->details.size(); i++)
   {
      char* name = (char*)mShape->names[mShape->details[i].nameIndex];

      if (dStrstr((const char*)dStrlwr(name), "collision-"))
      {
         mCollisionDetails.push_back(i);

         // The way LOS works is that it will check to see if there is a LOS detail that matches
         // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
         // the future). If it can't find a matching LOS it will simply use the collision instead.
         // We check for any "unmatched" LOS's further down
         mLOSDetails.increment();

      char buff[128];
         dSprintf(buff, sizeof(buff), "LOS-%d", i + 1);
         U32 los = mShape->findDetail(buff);
         if (los == -1)
            mLOSDetails.last() = i;
         else
            mLOSDetails.last() = los;
      }
   }

   // Snag any "unmatched" LOS details
   for (i = 0; i < mShape->details.size(); i++)
   {
      char* name = (char*)mShape->names[mShape->details[i].nameIndex];

      if (dStrstr((const char*)dStrlwr(name), "los-"))
      {
         // See if we already have this LOS
         bool found = false;
         for (U32 j = 0; j < mLOSDetails.size(); j++)
         {
            if (mLOSDetails[j] == i)
            {
               found = true;
               break;
            }
         }

         if (!found)
            mLOSDetails.push_back(i);
      }
   }

   // Compute the hull accelerators (actually, just force the shape to compute them)
   for (i = 0; i < mCollisionDetails.size(); i++)
         mShapeInstance->getShape()->getAccelerator(mCollisionDetails[i]);

	//=== Tuan end add.
   

   gClientContainer.addObject(this);
   gClientSceneGraph->addObjectToScene(this);

   return true;
}

an example to create a shape in script
put it at the end of PlayGUI::OnWake (playgui.cs)
%pNPCMarker = new ClientSideTSStatic()
            {
               shapeName = "starter.fps/data/shapes/player/player.dts";
               position = "195.826 117.462 223.813";
               rotate = "0 0 -1 88.2355";
               scale = "6.57362 7.48607 7.449463";
            };
#13
06/14/2006 (6:59 am)
Verry good resource!!! Thanx!!! One question, has someone modified this to use StaticShape instead of TSStatic, so we can for example change the skin of the object? Or is it not possible to use StaticShape?

Thanx
#14
07/30/2006 (11:39 am)
I have used the ConsoleFunction addClientSideTSStatic. It's great. How do i remove one again? Based on id or name or something. I'm having a click-to-walk game, and when you click it shows a little waypoint on the terrain... except i want it to dissappear again after he has reached that location or if he clicked again.

I found removeObjectFromScene,.. but how do i set that up for the script? I only need 1 thing per client.
#15
09/07/2006 (1:51 am)
Klass,

StaticShape derives from ShapeBase, TSStatic is a totally different beast. This resource aint about advanced objects that collide, take damage, move.. etc. They are static client side objects. I dont know why people keep asking, it says all this in the description or the comments afterwards.
#16
02/06/2007 (4:21 am)
Okay.... Is it possible to move this? Because a static is not really moveable.

I would like to use this as the start of my waypoint/Target directional arrow/pointer, and it seems to be the correct starting point.

How would I move/rotate this? Just add another ConsoleFunction? Then again comes the question of to what the Id or handle is. Any insight would be great...
#17
02/06/2007 (5:34 am)
Hi James

Movement can be dont using setTransform on the object inside the GUI code - on the same level as server side objects. But you will have to add console methods yourself and the needed interpolation code (if you want that).

I used this for a 3d target reticle that was moved to where the mouse pointed. It even pulsed with an animation.

What I would do in your case is to save a pointer to the object that you create in an array or hash array. Then generate id's yourself and use those as part of the console methods.
#18
02/06/2007 (5:59 am)
Wow... I have no idea how to do the Interpolation Code, was trying to avoid it... and hash arrays for the id's, I have no idea what that is or why I would use them, hehe.
This seems harder than I was hoping for.

But I'll poke it, and see if it moves.

What have you done for waypoints in Air Ace?
#19
02/06/2007 (11:18 am)
You only need the interpolation if you want smooth movement/rotation between setting new values for the transformation. If you want to use absolute positions/rotations, then you dont need it. E.g. you can use a dts that has an animation in it instead.

So there are ways to get around the math :-)

Else try to look in the item code - that has a simple rotation.

We dont have waypoints in Air Ace, as its a pure online deathmatch thing. So no need for it :-)
#20
02/06/2007 (11:21 pm)
Would you need Interpolation when the object is only ever on the client?
I always thought it's to make sure the movement is smooth between updates from the server.
It's beside the point... But I was just wondering.

Thanx for the replies.
Page «Previous 1 2 3 Last »