Eliminate the ghosts
by Gonzo T. Clown · in Torque Game Engine · 02/09/2006 (11:05 am) · 3 replies
Assuming that using DTS as Statics is completely out of the question, can someone shed some light on the easiest way to eliminate ghosting from a game that will never be networked?
I'm hoping I have just overlooked the obvious but I must eliminate ghosting to gain back the huge performance hit I'm losing from it.
TIA
I'm hoping I have just overlooked the obvious but I must eliminate ghosting to gain back the huge performance hit I'm losing from it.
TIA
About the author
#2
02/09/2006 (2:00 pm)
Want to know how much a performance hit you take with ghosting. Throw a 1000 ghosted objects into a mission, and then 500 non-ghosted objects into the same mission. Then hit your editor and watch the performance hit. You will instantly se what ghosting costs you. On a 2.6Ghz P4 running 1 gig of DDR400 ram I can get a 15 second lag by running the editor under those conditions. FPS without editor, 80FPS, with editor 12FPS. Once you crest a certain point the performanc hit becomes exponential. Keep in mind, ghosting an object requires it to be pack update written, pack delivered, pack update read. Three operations per ghosted object that could be eliminated completely. Take an interior for example. An interior is ghosted to keep a cheater from deleting the interior to see what is inside. Cheating is NOT a factor in this case at all because there is nothing to cheat for. So there is no reason whatsoever to have the interior ghosted. The static would be the most likely solution, but unfortunately, as far as I know, turning a DIF into a static is not an option either, lighting a DTS is different than lighting a DIF, and a non-ghosted DIF would be the ultimate solution here. Load it and use it would be the ultimate solution. Ghosting almost 1500 of them has finally put TGE to it's limits. And I've run out of other aeas to optimize. The Ghost set is going to have to get the boot.
#3
The first place you are going to want to start is in sim\netGhost.cc in NetConnection::activateGhosting(). At the top of this function add:
This will disable the ghosting altogether and execute the script callback that will allow the mission to finish loading (you could alternatively rewrite the scripts but I was aiming for as low an impact of a change as possible).
The next thing to tackle is to make sure all of the objects end up on the proper scenegraph, processlist, and container. The way I handled this was to create getClientSceneGraph(), getServerSceneGraph(), getClientProcessList(), getServerProcessList(), getClientContainer(), and getServerContainer(). I then replaced all of the references in the engine to gClientSceneGraph, gServerSceneGraph, gClientProcessList, gServerProcessList, gClientContainer, and gServerContainer with their respective getXXX functions. This allowed me to point everything to the server's scenegraph, processlist, and container when I was in singleplayer mode (in the end I ended up creating a separate set of these objects just for singleplayer but that was for a different reason and you can be fine keeping it all in the server's).
Next head over to sim\netGhost.h into NetObject::isClientObject() and put a return true; at the top of that function. This'll catch a lot of the client-side processing that is needed to prep an object for interpolation and rendering. You are going to have to go through some of the objects and fix their client-side checks to properly use this function (some of the code doesn't play nice). It can also be a good idea to put a return true; at the top of NetObject::isGhost() but I had a few issues with that and didn't need to in the end.
Next head over to game/gameConnection.cc in GameConnection::setControlObject(ShapeBase *obj) and add:
to the bottom of the function. This'll let the control object to get set up correctly when we are in singleplayer mode.
The last thing you are going to have to handle is making sure everything in clientProcess(timeDelta); and serverProcess(timeDelta); are getting called (merging the two functions works) as well as everything in ProcessList::advanceServerTime() and ProcessList::advanceClientTime() (again merging them works). Otherwise everything is going to get ticked twice!
Now you will have most everything in place (sorta). You will just have to start running the game and capturing crashes and dealing with the fall out =) This is messy and doable (I seem to recall a nasty crash in the ts animation code) but it is going to take time.
These are the basic steps I took to convert TGE into a purely singleplayer engine without totally rewrite/breaking everything (I even kept it switchable from singleplayer to multiplayer and back). It took me quite a while to get it all straight and I never did fix the last few bugs in the editor.
02/09/2006 (2:49 pm)
It isn't easy but it is doable. I can point you vaguely in the right direction but it requires so many changes to the engine there is no way I can detail them all.The first place you are going to want to start is in sim\netGhost.cc in NetConnection::activateGhosting(). At the top of this function add:
// Make sure that the script callbacks are getting called
Con::executef(this, 1, "onGhostAlwaysObjectsReceived");
Con::printf("Ghost Always objects received.");
return;This will disable the ghosting altogether and execute the script callback that will allow the mission to finish loading (you could alternatively rewrite the scripts but I was aiming for as low an impact of a change as possible).
The next thing to tackle is to make sure all of the objects end up on the proper scenegraph, processlist, and container. The way I handled this was to create getClientSceneGraph(), getServerSceneGraph(), getClientProcessList(), getServerProcessList(), getClientContainer(), and getServerContainer(). I then replaced all of the references in the engine to gClientSceneGraph, gServerSceneGraph, gClientProcessList, gServerProcessList, gClientContainer, and gServerContainer with their respective getXXX functions. This allowed me to point everything to the server's scenegraph, processlist, and container when I was in singleplayer mode (in the end I ended up creating a separate set of these objects just for singleplayer but that was for a different reason and you can be fine keeping it all in the server's).
Next head over to sim\netGhost.h into NetObject::isClientObject() and put a return true; at the top of that function. This'll catch a lot of the client-side processing that is needed to prep an object for interpolation and rendering. You are going to have to go through some of the objects and fix their client-side checks to properly use this function (some of the code doesn't play nice). It can also be a good idea to put a return true; at the top of NetObject::isGhost() but I had a few issues with that and didn't need to in the end.
Next head over to game/gameConnection.cc in GameConnection::setControlObject(ShapeBase *obj) and add:
GameConnection * toServer = GameConnection::getServerConnection(); toServer->setControlObject(obj);
to the bottom of the function. This'll let the control object to get set up correctly when we are in singleplayer mode.
The last thing you are going to have to handle is making sure everything in clientProcess(timeDelta); and serverProcess(timeDelta); are getting called (merging the two functions works) as well as everything in ProcessList::advanceServerTime() and ProcessList::advanceClientTime() (again merging them works). Otherwise everything is going to get ticked twice!
Now you will have most everything in place (sorta). You will just have to start running the game and capturing crashes and dealing with the fall out =) This is messy and doable (I seem to recall a nasty crash in the ts animation code) but it is going to take time.
These are the basic steps I took to convert TGE into a purely singleplayer engine without totally rewrite/breaking everything (I even kept it switchable from singleplayer to multiplayer and back). It took me quite a while to get it all straight and I never did fix the last few bugs in the editor.
Associate Manoel Neto
Default Studio Name
But, to answer your question, no, there is no easy way to eliminate the ghosting stuff. You could write a replacement base class that does all of it's stuff in the client or something like that, and modify all classes you'll use in your game to cope with the changes. You could hack the netGhost stuff to pass the server object directly when sending ghosts (using the same object both as serverObject and clientObject). Or hack the advanceClientTime funciton and make it update the objects as if they were both serverObjects and clientObjects.
All those options would surely bring lots of unexpected problems to deal with, and all them require a deep understanding of the TGE server-client update flow, and it is hard to predtic how much time one would need to do all those changes, and how much performance that would improve.