Game Development Community

SimObject Id and client/server connection

by Frank Bignone · in Torque Game Engine · 05/07/2002 (8:19 am) · 15 replies

Here is my question. How can I transmit to the server id of an object i'm inspecting on a client ?

Let's say that on a client, i'm looking at some object. I can get their id by object->getId(); but if I use that id on the server with Sim::findObject(id,toto) I cannot retrieve the object (toto is always NULL) !

So, How can I do it please ?

About the author

Real programmers don't waste time recompiling; they patch the binary files... ... Real programmers don't waste time patching binary files; they patch memory.


#1
05/07/2002 (1:53 pm)
One way to do it, although it is a real pain to do, is to make a property as a holder for this value and then transfer it in packdata.

Another way would be to output the value to a script function and transfer it to the server using a CommandToServer call in script.

I am sure there would be a better way than this to do it in the engine but I am not that great at C++ sorry :/
#2
05/07/2002 (2:12 pm)
Although I've not messed with these they seem pretty self explanatory.

You could try:-

NetObject *NetConnection::resolveGhostParent(S32 id);
NetObject *NetConnection::resolveGhost(S32 id);
S32 NetConnection::getGhostIndex(NetObject *obj);

.. which provide mappings for ghosts.

If you search the codebase there should be plenty of examples for their usage.

Hope this helps.

- Melv.
#3
05/07/2002 (2:25 pm)
Melv, I tried it and it did not solve my pb
Maybe I used it in a wrong manner
#4
05/07/2002 (4:35 pm)
how bout this one:
class NetObject
{
...
U32 getNetIndex() { return mNetIndex; }
#5
05/07/2002 (8:18 pm)
iv tried this too and would really like to see input(any Employee's out there hint hint..hehe)!!

What iv done to get by this problem is to just resolved the id on server and passed info u need to ghost through unpackupdate packupdate.

but i dont like the idea of more network transfers
#6
05/08/2002 (6:07 am)
I posted a resource for object picking some time ago and used the methods Melv is referring to in a way that I think might be useful to you. Take a look, and if you still have questions let me know.

Dave Myers
21-6 Productions
#7
05/08/2002 (9:03 am)
I tried using something similar to your resource but it crashed my appli with no chance to debug it. I will give it a second try this week. Thanks
#8
05/08/2002 (1:17 pm)
ahh i see so:

//on server pass ghostindex:
gIndex = getGhostIndex(mSelectedObj);
bstream->writeInt(gIndex,10);



//on client resolve obj from index:
ShapeBase* obj = static_cast(resolveGhost(gIndex));

nice a simple looking..:) thanks David
#9
11/18/2005 (7:14 am)
This is only half of the story, however. Doesn't passing a reference from client to server require a different sequence of calls?

Can someone write out how a NetEvent would pass a reference bidirectionally? I am going to solve this once and once only, and create

// does what it says, not caring if run on server or client, thankyouverymuch
void BitStream::writeNetObjectReference(NetObject *forMe, NetConnection *toBeSentOverThisConnection);

// returns false if the object is NOT null but we do not yet have a ghost image of it -- if such an error is possible??
bool BitStream::readNetObjectReference(NetObject **out, NetConnection *receivedOverThisConnection);

This is as common a need as writing or reading an int, and yet I still cannot find an example of this working in the NetEvents shipped with TGE. It should not require an understanding of implementation, or more than a single call. Please help me write this function pair?

tone
#10
11/18/2005 (10:13 am)
If you mean "ObjectID" when you speak of "reference" above, then the networking code already does this for you--you simply need to resolve in each direction as appropriate.

Keep in mind that each client has a unique and non-consistent GhostID for every object that is ghosted for it, and the server (and client) both have script ConsoleMethods, as well as engine methods as part of the NetConnection/GameConnection class for proper resolution of the indexes.
#11
11/20/2005 (11:42 am)
Can you please post code that will do what you're suggesting, as I have no idea what solution you are trying to steer me toward. I have a CS and engineering degree and years of C++ experience, but the vagueness and ambiguity of the TGE code is thwarting me left and right.

Consider trying to learn what these things are from the documents... it's as though they're trying to make a visible display of showing me how to use the API without actually helping me.

Consider:

U32 	getNetIndex ()
 	Get the ghost index of this object. 
bool 	isServerObject () const
 	Is this a server object? 
bool 	isClientObject () const
 	Is this a client object? 
bool 	isGhost () const
 	Is this is a ghost?

This documentation creates more questions than it answers. Why does getNetIndex() return the ghost index? Are they different things, or the same? or something else? Is a ghost simply the version of a NetObject that resides on both server and client? If so, why not tell me what happens if this is run on the server? Is a ghosted object on the server itself called a ghost? Why isn't this done more in the following form:

[code]
U32 getClientObjectID()
Returns the "ghost ID" of the NetObject on the client running the code. A NetObject which is ghosted on clients (from the server) has a different ghostIndex by which each client refers to it. Returns 0 if called on the Server, as a NetObject on the server is not a ghosted copy.
U32 getServerObjectID()
Returns the canonical object index for efficient storage and reference on the server. This returns 0 if called on a client-only object, as the TGE network security model does not permit direct reference to objects on the server -- such reference should be made by the ClientObjectID
bool isServerObject () const
A NetObject, whether or not it is ghosted, will return true if the code is being run on the server.
bool isClientObject () const
If your NetObject is a ghost copy of a NetObject on the server, this will return true. It will also return true if it is a NetObject that only resides on your client. Always false for NetObjects examined from the server's code.
bool isGhost () const
On a client application, returns true only if your view of the NetObject is a ghost projected from the server. Calling this on the server always returns false, but servers can tell if a given object has ghost images on any clients by isGhostedToClients() and whether they are eligible for ghosting via isGhostingActivated()/
[code]


tone
#12
11/20/2005 (6:40 pm)
A ghost is a client copy of an object. The index is used to turn a server id into a client id. Each client has unique object client ids.

Torque is definitely a "learn by doing" kind of project. Questions I always ask myself are:

1. What am I trying to do?
2. Is there somewhere else in the engine that does a similar thing? If so, steal it and learn from it. If not, find the closest thing and use it as a starting point.

From your original post, it looks like your trying to pass the object id from a client up to the server. Why? I haven't run into this need yet, so maybe there's another way to accomplish your task?

However, you should be able to get the netindex of the client object, push it up to the server, then resolve the object id as you would on a client. The mount code in ShapeBase is a good place to see similar things in action. (Thanks to Josh "The Force" Moore for pointing me at that recently)
#13
11/21/2005 (5:08 am)
You may want to look at the TDN article on Torque Networking, specifically the section on Ghosting.

The short answer is: send your client's object ID up to the server (normally via a cmdToServer script call, but not always), and then on the server use NetConnection::resolveObjectFromGhostIndex() to return a pointer to the server's authoritative object that is associated with the client's clientID.
#14
12/02/2005 (11:59 am)
I appreciate your help, but I do not see any clear-cut cases in the code which answer the question, and trying out code when other factors might get in the way is arduous when one has many other open questions. I would love it if you could cast your eye over the following code I have written in an effort to make it easy to simply write a read/write method on BitStream.

Will this work?

// write out a reference that the other side should be able to resolve to a pointer
// no matter which side of the connection this code is run from
// so that no pack()/unpack() routines need conditional behaviors based on whether they
// are run on client or on server
void 
BitStream::writeNetObjectReference(NetObject *n, NetConnection *conn)
{
    if (writeFlag(n != NULL)) {
        // if we are on the client
        if (conn->isConnectionToServer()) {
            writeRangedU32(n->getId(), 0, NetConnection::MaxGhostCount); 
        } else {
            S32 id = conn->getGhostIndex(n);
            AssertFatal(id != -1, "writeNetObjectReference() called on
object with no ghost index");    
            writeRangedU32(U32(id), 0, NetConnection::MaxGhostCount);
        }            
    }
}

// inverse of above function, returns false
// if the object referenced is known to be non-null yet no corresponding object
// on this network node can be found
bool 
BitStream::readNetObjectReference(NetConnection *conn, NetObject **out)
{
    if (readFlag()) {
        // if we are on the client
        if (conn->isConnectionToServer()) {
            U32 ghostIndex = readRangedU32(0,NetConnection::MaxGhostCount);
            *out = dynamic_cast<NetObject*>(conn->resolveGhost(ghostIndex));
        } else {
            U32 ghostIndex = readRangedU32(0,NetConnection::MaxGhostCount);
            *out = dynamic_cast<NetObject *>(conn->resolveObjectFromGhostIndex(ghostIndex));
        }        
        return out != NULL;
    } else {
        *out = NULL;
        return true;
    }
}
#15
12/02/2005 (12:00 pm)
I saw Frank's name pop up in unread posts and got all excited...

)C: