Get interior object id on a client.
by Klaas Hemerijckx · in Torque Game Engine · 09/09/2006 (3:02 am) · 16 replies
Hi,
I have defined an interior object in the mission file like this:
new SimGroup(Towers) {
new InteriorInstance(WaterTower1) {
position = "325.43 161.116 224.178";
rotation = "0 0 -1 85.9439";
scale = "1 1 1";
interiorFile = "~/data/interiors/towers/watertower.dif";
showTerrainInside = "0";
};
};
On the server I can get the id with: WaterTower1.getId();
But when I use WaterTower1.getId() on the client it can not find the interior object.
How should I get the interior object id on the client?
Thanx,
Klaas
I have defined an interior object in the mission file like this:
new SimGroup(Towers) {
new InteriorInstance(WaterTower1) {
position = "325.43 161.116 224.178";
rotation = "0 0 -1 85.9439";
scale = "1 1 1";
interiorFile = "~/data/interiors/towers/watertower.dif";
showTerrainInside = "0";
};
};
On the server I can get the id with: WaterTower1.getId();
But when I use WaterTower1.getId() on the client it can not find the interior object.
How should I get the interior object id on the client?
Thanx,
Klaas
#2
You would have to enter the Ghost Index and grab the correct ID before sending it to the client, and even then it is very inefficent because you should just be able to do this on the client locally, no need to ask the server for it.
09/09/2006 (4:06 am)
That wont work. The server has its own set of object ID's and the client has its own set of Ghost ID's. You cannot share these between them (and you shouldnt, for security reasons), because they do not exist on the client.You would have to enter the Ghost Index and grab the correct ID before sending it to the client, and even then it is very inefficent because you should just be able to do this on the client locally, no need to ask the server for it.
#3
You seem to have a firm grasp on Torque's networking code, would you be able to rewrite my code in the fashion that you describe above and post here? Please, it would be a useful learning experience for me and others that stumble across this thread.
09/09/2006 (4:11 am)
I don't know enough to argue with you Stefan but I do know it does work. I tested it before posting.You seem to have a firm grasp on Torque's networking code, would you be able to rewrite my code in the fashion that you describe above and post here? Please, it would be a useful learning experience for me and others that stumble across this thread.
#4
09/09/2006 (4:14 am)
Quote:Unless you have the working code to back that up, I disagree with you on that one. The client accesses all information from the server does it not, so how can the client obtain information from itself that does not exist?
you should just be able to do this on the client locally, no need to ask the server for it.
#5
Work as in, what? You can echo it? Or actually use it? If the latter then I bet you are on a listening server enviorment rather than a dedicated one. And please do argue with me if you disagree :) I can make mistakes just like anyone else.
I have working code to back it up, but I dont have to. And no, the client does not obtain all the information from the server. I suggest you read up on Ghosting.
These are the functions you have to use in script:
resolveObjectFromGhostIndex ( ghostIDx )
getGhostID ( ghostID )
resolveGhostID ( realID )
09/09/2006 (4:31 am)
Hi Tim,Quote:
I don't know enough to argue with you Stefan but I do know it does work. I tested it before posting.
Work as in, what? You can echo it? Or actually use it? If the latter then I bet you are on a listening server enviorment rather than a dedicated one. And please do argue with me if you disagree :) I can make mistakes just like anyone else.
Quote:
Unless you have the working code to back that up, I disagree with you on that one. The client accesses all information from the server does it not, so how can the client obtain information from itself that does not exist?
I have working code to back it up, but I dont have to. And no, the client does not obtain all the information from the server. I suggest you read up on Ghosting.
These are the functions you have to use in script:
resolveObjectFromGhostIndex ( ghostIDx )
getGhostID ( ghostID )
resolveGhostID ( realID )
#6
09/09/2006 (4:41 am)
This is the essential part of what we discussed:Quote:
When a new object comes into scope for a specific client, the server assigns a GhostID to this object, and only tells the client what it's unique GhostID is. In other words, the client is never told the actual server ObjectID of the newly scoped object, but instead is only told what the GhostID is for just that client. This means that two clients may be observing the exact same object, but the server has given them two completely different GhostID's for the exact same object--so there is no easy way for two clients to collude and gain an advantage.
Since the server is the only side that has knowledge of both the GhostID and the actual ObjectID it is mapped for, the developer is responsible for managing any communcations between client and server that involve Object/GhostID's. The networked updates takes care of this automatically, but if you are using any RPC command functionality (commandToServer, commandToClient, etc.), then you will need to make sure that the ID numbers are in synch.
#7
Here's what's baking my noodle though. Everything you say seems to make sense to me, however I tested my above code and it still works?
Whether across a LAN, one PC hosting the other joining. Across the net using GG's test server, or using a dedicated server, the ID is always echoed no matter what machine the cmd is executed from and the ID is always the same. In my case 1094.
So what gives? My code is implemented poorly but by some fluke it still actually works, lucky me I guess.
I've always had a vague idea of what ghosting is, though just assumed that it was behind the scenes stuff I didn't have to worry about. I've never seen a game use it in script for any functions apart from mission loading etc, not even Tribes.
Off to do some research.
09/09/2006 (4:46 am)
Ok, read up I shall. Thanks for the nudge in the right direction.Here's what's baking my noodle though. Everything you say seems to make sense to me, however I tested my above code and it still works?
Whether across a LAN, one PC hosting the other joining. Across the net using GG's test server, or using a dedicated server, the ID is always echoed no matter what machine the cmd is executed from and the ID is always the same. In my case 1094.
So what gives? My code is implemented poorly but by some fluke it still actually works, lucky me I guess.
I've always had a vague idea of what ghosting is, though just assumed that it was behind the scenes stuff I didn't have to worry about. I've never seen a game use it in script for any functions apart from mission loading etc, not even Tribes.
Off to do some research.
#8
I'v solved my problem but a roundrip to the server is nescessary because the client does not know the object name (ex. WaterTower1). Here is the code:
Put this on the client:
Put this on the server:
Now you can request the client (ghost) id by executing:
requestObjectIdByName("name of the object for example WaterTower1");
This gives you the right id on the client to do some manipulations.
Thanx again,
Klaas
09/09/2006 (5:05 am)
Thanx Stefan & Tim for the quick reply's. I'v solved my problem but a roundrip to the server is nescessary because the client does not know the object name (ex. WaterTower1). Here is the code:
Put this on the client:
//Send an object name to the server to request his id.
function requestObjectIdByName(%objectname)
{
commandToServer('ObtainObjectServerID', %objectname);
}
//Convert a received server object id to the (ghost) id of the client.
function clientCmdreceiveObjectIdByName(%srvObjectId)
{
%clObj = ServerConnection.resolveGhostId(%srvObjectId);
echo( "","Client ghost ID = " @ %clObj );
}Put this on the server:
//Send a server object id to the client based on a name.
function serverCmdObtainObjectServerID(%client, %objectname)
{
%ObjectID = %client.getGhostID(%objectname.getID());
commandToClient(%client,'receiveObjectIdByName', %ObjectID);
}Now you can request the client (ghost) id by executing:
requestObjectIdByName("name of the object for example WaterTower1");
This gives you the right id on the client to do some manipulations.
Thanx again,
Klaas
#9
Thanks for taking the time to post your solution too.
Tim.
09/09/2006 (5:36 am)
Cool, glad we were able to help =)Thanks for taking the time to post your solution too.
Tim.
#10
Yes! :) You will be able to echo the ID, but if you do a isObject ( ID ) or try to actually call functions with that very ID, you'll either get an error or access the wrong object. ID's in scripts are just strings.
I hear ya, and I agree. It puzzled me for some time too. The functions which required this in Tribes II were most likely in-engine.
@ Klaas:
I'm happy we could help. As long as you dont use the above code at a very frequent rate or expect the response to be fast, it's all good. You are right in that Object Names are not transfered from the server to the client, which would be an easy fix and something I would like as well.
Nevertheless, glad it works for you!
Edit: My spelling sucks.
09/09/2006 (5:51 am)
@ Tim:Quote:
Ok, read up I shall. Thanks for the nudge in the right direction.
Here's what's baking my noodle though. Everything you say seems to make sense to me, however I tested my above code and it still works?
Whether across a LAN, one PC hosting the other joining. Across the net using GG's test server, or using a dedicated server, the ID is always echoed no matter what machine the cmd is executed from and the ID is always the same. In my case 1094.
Yes! :) You will be able to echo the ID, but if you do a isObject ( ID ) or try to actually call functions with that very ID, you'll either get an error or access the wrong object. ID's in scripts are just strings.
Quote:
I've always had a vague idea of what ghosting is, though just assumed that it was behind the scenes stuff I didn't have to worry about. I've never seen a game use it in script for any functions apart from mission loading etc, not even Tribes.
Off to do some research.
I hear ya, and I agree. It puzzled me for some time too. The functions which required this in Tribes II were most likely in-engine.
@ Klaas:
Quote:
Thanx Stefan & Tim for the quick reply's.
I'v solved my problem but a roundrip to the server is nescessary because the client does not know the object name (ex. WaterTower1). [...]
I'm happy we could help. As long as you dont use the above code at a very frequent rate or expect the response to be fast, it's all good. You are right in that Object Names are not transfered from the server to the client, which would be an easy fix and something I would like as well.
Nevertheless, glad it works for you!
Edit: My spelling sucks.
#11
I'm glad I found out about this now. I'd hate to have to redo all of my scripts over again.
09/09/2006 (6:05 am)
Quote:The light is starting to shine!
Yes! :) You will be able to echo the ID, but if you do a isObject ( ID ) or try to actually call functions with that very ID, you'll either get an error or access the wrong object. ID's in scripts are just strings.
I'm glad I found out about this now. I'd hate to have to redo all of my scripts over again.
#12
09/09/2006 (6:55 am)
Hehehe :) Have fun!
#13
Stefan pointed you in the right direction (the TDN articles on networking and ghosting), but something to keep in mind:
Normally, you want to be very very careful about accessing objects via their ID's (or even names) on the client, unless they are client side only objects, specifically things like GUI's.
The reason for this is summarized above, but a relatively hidden detail makes it really dangerous: When a ghosted object goes out of scope for a particular client, the object will soon be destroyed on that client. If/when the same server object comes back into scope for that client, it will be created again on the client, most likely with a different GhostID.
Any storage of GhostID's on clients can very easily become stale, and for the most part if you are writing script that requires GhostID's, then you may be going about things improperly.
The operating theory that should be understood here is that objects that are ghosted to a client result in a non-authoritative, not-guaranteed-to-always-be-around copy of the object on that client.
09/09/2006 (11:08 pm)
Good discussion, sorry I dropped in late.Stefan pointed you in the right direction (the TDN articles on networking and ghosting), but something to keep in mind:
Normally, you want to be very very careful about accessing objects via their ID's (or even names) on the client, unless they are client side only objects, specifically things like GUI's.
The reason for this is summarized above, but a relatively hidden detail makes it really dangerous: When a ghosted object goes out of scope for a particular client, the object will soon be destroyed on that client. If/when the same server object comes back into scope for that client, it will be created again on the client, most likely with a different GhostID.
Any storage of GhostID's on clients can very easily become stale, and for the most part if you are writing script that requires GhostID's, then you may be going about things improperly.
The operating theory that should be understood here is that objects that are ghosted to a client result in a non-authoritative, not-guaranteed-to-always-be-around copy of the object on that client.
#14
Stefan, FYI, i've solved the roundtrip problem with transfering the object name to the client.
In the packUpdate function (*.cc file) of your object add this:
In the unpackUpdate function (*.cc file) of your object add this:
Now you can access an object on the client with his name and without a roundtrip to the server.
Klaas
09/11/2006 (4:37 am)
Thanx for the info Stephen, I will keep it in mind.Stefan, FYI, i've solved the roundtrip problem with transfering the object name to the client.
In the packUpdate function (*.cc file) of your object add this:
stream->writeString(this->getName());
In the unpackUpdate function (*.cc file) of your object add this:
const char *dataBlockName; ... dataBlockName = stream->readSTString(); this->assignName(dataBlockName);
Now you can access an object on the client with his name and without a roundtrip to the server.
Klaas
#15
Either stuff it into the initialUpdateMask (shapeBase) or make a mask of your own. A mask makes sure the packet is only sent when the mask has been set. This let's you control when to packet stuff and send it away - like in this case, only when the object is created (or if you wish, when the object changes names).
09/11/2006 (6:03 am)
Remember, that will send the name each tick!Either stuff it into the initialUpdateMask (shapeBase) or make a mask of your own. A mask makes sure the packet is only sent when the mask has been set. This let's you control when to packet stuff and send it away - like in this case, only when the object is created (or if you wish, when the object changes names).
#16
09/11/2006 (7:24 am)
I used a mask (forgot to put it in the code extract).
Torque Owner Tim Heldna
- Start a function on the client which sends a command to the server.
- Server command then obtains the client, jumps to another server command and retrieves the ID.
- ID is then sent from server back to client.
Example.
Put this on client:
function requestWaterTowerID() { commandToServer( 'ObtainWaterTowerID' ); } function clientCmdReceiveWaterTowerID(%WaterTowerID) { echo( "","WaterTower ID received from server. ID = " @ %WaterTowerID ); }Put this on server:
function serverCmdObtainWaterTowerID(%client) { %client.ObtainWaterTowerID(); } function GameConnection::ObtainWaterTowerID(%client) { %WaterTowerID = WaterTower1.getID(); echo( "","Obtaining WaterTower ID from server. ID = " @ %WaterTowerID ); commandToClient( %client,'receiveWaterTowerID', %WaterTowerID ); }Now, whether you are on the server or the client, type this into the console to retrieve your ID:
If you know how to copy and paste code, the console will echo the "WaterTower1" Id to you.
Let me know if this helps.
-Tim.