NetObject and GhostID problem
by Gordon Marsh · in Torque Game Engine · 10/13/2006 (7:51 am) · 8 replies
All,
I was trying to change a part of my game over from script commands to net events but have come unstuck.
Basically all I'm trying to do is pass the players ghost ID to the server so that it can perform some operations, so in Player.cc I have:
then in the NetEvent (which I have called ChatChangeEvent) :
All of this works fine, the ghostID created by the client is passed to the server properly, but mShape is always null. So I guess either I am creating the wrong ghostID in the first place, or I am using it incorrectly in unpack...
I'm sure this is a small error, but I'm totally stuck now!
Thanks, Gords
I was trying to change a part of my game over from script commands to net events but have come unstuck.
Basically all I'm trying to do is pass the players ghost ID to the server so that it can perform some operations, so in Player.cc I have:
void Player::sendChatUpdateToServer()
{
NetConnection* conn = NetConnection::getConnectionToServer();
ChatChangeEvent* pEvent = new ChatChangeEvent();
..........
pEvent->theGhostID = conn->getGhostIndex(this);
conn->postNetEvent( pEvent );
}then in the NetEvent (which I have called ChatChangeEvent) :
void ChatChangeEvent::pack(NetConnection* con, BitStream* stream)
{
stream->writeFlag(true);
stream->writeString(talkText, maxTextLen);
stream->writeString(isTalking, 5);
stream->writeInt(theGhostID,NetConnection::GhostIdBitSize);
stream->writeFlag( false );
}
void ChatChangeEvent::unpack(NetConnection* con, BitStream* stream)
{
// Parse out data
Con::printf("Recieved chat message... processing");
if(!stream->readFlag()) return;
stream->readString(talkText);
stream->readString(isTalking);
theGhostID = stream->readInt(NetConnection::GhostIdBitSize);
Con::printf("1 Recieved chat message %s from %i with %s", talkText, theGhostID, isTalking);
// Use data to update player on the server side
Player* mShape = dynamic_cast<Player*>(con->resolveObjectFromGhostIndex(theGhostID));
Con::printf("Player sending is... %s", mShape->getName());
mShape->setChatText(talkText);
mShape->setIsTalking(isTalking);
}All of this works fine, the ghostID created by the client is passed to the server properly, but mShape is always null. So I guess either I am creating the wrong ghostID in the first place, or I am using it incorrectly in unpack...
I'm sure this is a small error, but I'm totally stuck now!
Thanks, Gords
#2
10/13/2006 (8:23 am)
And you also never need to send the ghost ID from a particular client to the server. The server is what assigns ghost ID's, and keeps a mapping of them already.
#3
must be incorrect.
Obviously I am passing in the clients ObjectID into resolveObjectFromGhostIndex, and I take it it is expecting a ghostID. So I then looked at doing:
but getGhostIndex wants a NetObject* and I only have an objectID/SimObjectID.
On a different note, some of the docs surrounding this are very confusing.
tdn.garagegames.com/wiki/Torque/Networking/Ghosting
clearly indicates that a client can send a ghostID.
10/13/2006 (11:29 am)
Thanks guys, I'm still getting a crash though at the same point. The line:Player* mShape = dynamic_cast<Player*>(con->resolveObjectFromGhostIndex(theGhostID));
must be incorrect.
Obviously I am passing in the clients ObjectID into resolveObjectFromGhostIndex, and I take it it is expecting a ghostID. So I then looked at doing:
S32 sGhostID = con->getGhostIndex(xxxx); Player* mShape = dynamic_cast<Player*>(con->resolveObjectFromGhostIndex(sGhostID));
but getGhostIndex wants a NetObject* and I only have an objectID/SimObjectID.
On a different note, some of the docs surrounding this are very confusing.
tdn.garagegames.com/wiki/Torque/Networking/Ghosting
clearly indicates that a client can send a ghostID.
#4
The way to think of it is:
Client has a big list of objects it knows about, these objects are identified by a GhostID (server assigns this)
The server contains a big list of all objects, these all are identified by a serverID (I think there's a proper name for that but off hand I can't think of it).
The server also contains a number of other lists (one for each client). These lists contain a map which can be used to translate a serverID to the ghostID the server assigned originally when it ghosted that object to that specific client (emphasis on "specific client")
The ghost id's that map to a given server id are different for each client. The server does this to prevent cheating, since a player with ghostID 5654 on one client will not be the same object if you try that id on another client. Only the server knows the specific id an object will have on each client (which is where getGhostIndex comes in, the server can use this to determine what the ghostID for a _specific_ client is for a given server object)
In regards to your crash, have you run this in a debugger to locate exactly what is causing the crash? Is mShape null after the dynamic cast?
Also, are you sure you need to be sending a player id in the first place? Could you not instead just send the message with no id, then have the server find the current control object for the client and test if it's a player then use that object. Assuming the client is sending the text message for a player they're in control of? Send chat update could then be moved from player to the gameConnection.
10/13/2006 (3:53 pm)
GetGhostIndex wants a netObject because it is a server side function that is used to map a server object ID to a ghost id prior to sending the id to a client.The way to think of it is:
Client has a big list of objects it knows about, these objects are identified by a GhostID (server assigns this)
The server contains a big list of all objects, these all are identified by a serverID (I think there's a proper name for that but off hand I can't think of it).
The server also contains a number of other lists (one for each client). These lists contain a map which can be used to translate a serverID to the ghostID the server assigned originally when it ghosted that object to that specific client (emphasis on "specific client")
The ghost id's that map to a given server id are different for each client. The server does this to prevent cheating, since a player with ghostID 5654 on one client will not be the same object if you try that id on another client. Only the server knows the specific id an object will have on each client (which is where getGhostIndex comes in, the server can use this to determine what the ghostID for a _specific_ client is for a given server object)
In regards to your crash, have you run this in a debugger to locate exactly what is causing the crash? Is mShape null after the dynamic cast?
Also, are you sure you need to be sending a player id in the first place? Could you not instead just send the message with no id, then have the server find the current control object for the client and test if it's a player then use that object. Assuming the client is sending the text message for a player they're in control of? Send chat update could then be moved from player to the gameConnection.
#5
Works like a charm... I have no idea why the resolveObjectFromGhostIndex wasn't working (it never returned a NetObject*), and I'm sure ghostobjectID will come back to haunt me (pun intended).
Thanks,
Gords
10/13/2006 (4:25 pm)
Thanks for the ID info Gary... but more so for the different slant on how to get the players details... I've scrapped the whole ghost ID thing and put into unpack:// Use data to update player on the server side
GameConnection* temp = dynamic_cast<GameConnection*>(con);
if(temp) {
Con::printf("Converted to a GameConnection object...");
ShapeBase* shp = temp->getControlObject();
if(shp) {
Con::printf("Converted to a Shapebase object...");
Player* mShape = dynamic_cast<Player*>(shp);
if(mShape) {
Con::printf("Converted to a player object...");
mShape->setChatText(talkText);
mShape->setIsTalking(isTalking);
}
}
}Works like a charm... I have no idea why the resolveObjectFromGhostIndex wasn't working (it never returned a NetObject*), and I'm sure ghostobjectID will come back to haunt me (pun intended).
Thanks,
Gords
#6
Glad you got it working out in a cleaner manner however :)
10/13/2006 (11:15 pm)
ResolveObjectFromGhostIndex was almost certainly returning a SimObject *, which would need to be cast to a NetObject * to be used as a NetObject.Glad you got it working out in a cleaner manner however :)
#7
I came up against another issue needing to pass the ghostID. The solution I came up with was as follows:
1. Player hits button in a GUI and the Torquescript code calls getGhostID on the object in question.
2. This ghostID is passed into the engine via a ConsoleMethod.
3. The ConsoleMethod initiates a netevent that passes the ghostID to the server.
4. The server can then call con->resolveObjectFromGhostIndex(GhostID) and cast it to a ShapeBase object.
The server can then operate on the ShapeBase object as required.
Am I going mad here? I am calling getGhostID on the client and my code works fine. But above you say only the server keeps such IDs. Do I take it that the script "getGhostID" either makes a call to the server or infact is misleadingly named and returns a SimID?
As I said, my code is working, I'm just asking for clarity.
Gords
10/19/2006 (4:44 pm)
Stephen, I have my code working as required so this is more a discussion point.I came up against another issue needing to pass the ghostID. The solution I came up with was as follows:
1. Player hits button in a GUI and the Torquescript code calls getGhostID on the object in question.
2. This ghostID is passed into the engine via a ConsoleMethod.
3. The ConsoleMethod initiates a netevent that passes the ghostID to the server.
4. The server can then call con->resolveObjectFromGhostIndex(GhostID) and cast it to a ShapeBase object.
The server can then operate on the ShapeBase object as required.
Am I going mad here? I am calling getGhostID on the client and my code works fine. But above you say only the server keeps such IDs. Do I take it that the script "getGhostID" either makes a call to the server or infact is misleadingly named and returns a SimID?
As I said, my code is working, I'm just asking for clarity.
Gords
#8
The reason for this is that the client knows about one and only one ID at all, and that is the ID the client side simulation is told to assign by the server when it is told by the networking to create a new object--which will be the GhostID for that client.
The server on the other hand keeps track of the authoritative versions of all objects, and we refer to these objects via their ObjectID. In addition, when any of these objects come in to scope for a specific client, a GhostID is stored on that client's GameConnection, matched to the "real" ObjectId on the server, and then sent to the client as part of the ghosting system for the client to instantiate in their non-authoritative copy of the server simulation.
It's honestly a matter of semantics, but with something as complex as the networking system, in my opinion it's best to be pedantic with your terms!
10/19/2006 (9:41 pm)
GetGhostID has no actual meaning on the client side of the equation...from your observed results (not confirmed by looking at the source code, it's late and I'm very tired!), it simply short circuits to the client's SimID.The reason for this is that the client knows about one and only one ID at all, and that is the ID the client side simulation is told to assign by the server when it is told by the networking to create a new object--which will be the GhostID for that client.
The server on the other hand keeps track of the authoritative versions of all objects, and we refer to these objects via their ObjectID. In addition, when any of these objects come in to scope for a specific client, a GhostID is stored on that client's GameConnection, matched to the "real" ObjectId on the server, and then sent to the client as part of the ghosting system for the client to instantiate in their non-authoritative copy of the server simulation.
It's honestly a matter of semantics, but with something as complex as the networking system, in my opinion it's best to be pedantic with your terms!
Torque Owner Gary Preston
Clients only store/use ghost Ids, so simply set pEvent->ghostId to this->getId();