Making a "Fat connection
by Phil Carlisle · in Torque Game Engine · 12/27/2005 (6:37 pm) · 14 replies
I'm tackling part of my game which requires up to 4 players on a single machine AND network capability..
so Ive been thinking, my best approach seems to be to derive a class from GameConnection which uses a class derived from Move called "FatMove" and this allows me to pack up a whole load more data in the getNextMove call etc.
At the Connection side, I'll have to add methods to add a Control object into a list or fixed array (probably fixed array as the move has to have a finite size no matter what) and methods which tell me which control object are allowed to access which areas of a move.. So for instance add an index value into the control object which it passes when it calls the "getMove" function and which returns the specific parts of the move I'm interested in.
Does this seem like a good idea to you guys?
So my move struct will basically be 4 keyboards worth of input..
the GameConnection derived class will be responsible for demuxing the move packet and passing that onto the correct control objects (which it now has up to 4 of).
Seems the simplest/fastest/cleanest method.. but if anyone can suggest another.
My only other alternative is to create a local connection for each local player, but that doesnt help as the movemanager would still read the same console vars to pack up each move.. not different areas of the keyboard.
so Ive been thinking, my best approach seems to be to derive a class from GameConnection which uses a class derived from Move called "FatMove" and this allows me to pack up a whole load more data in the getNextMove call etc.
At the Connection side, I'll have to add methods to add a Control object into a list or fixed array (probably fixed array as the move has to have a finite size no matter what) and methods which tell me which control object are allowed to access which areas of a move.. So for instance add an index value into the control object which it passes when it calls the "getMove" function and which returns the specific parts of the move I'm interested in.
Does this seem like a good idea to you guys?
So my move struct will basically be 4 keyboards worth of input..
the GameConnection derived class will be responsible for demuxing the move packet and passing that onto the correct control objects (which it now has up to 4 of).
Seems the simplest/fastest/cleanest method.. but if anyone can suggest another.
My only other alternative is to create a local connection for each local player, but that doesnt help as the movemanager would still read the same console vars to pack up each move.. not different areas of the keyboard.
About the author
Recent Threads
#2
I've made it work by packing one larger move (modding the move struct to accomodate 4 players worth of input) and then de-multiplexing that single large move on the server side.
But it does feel a bit hacky.
Are you suggesting something else? track 4 individual moves and then how would you feed them into the player, surely the credit stuff for the moves would be more hassle there than anything.
01/01/2006 (3:09 am)
Do you mean pack a single large move or 4 moves one after the other Ben?I've made it work by packing one larger move (modding the move struct to accomodate 4 players worth of input) and then de-multiplexing that single large move on the server side.
But it does feel a bit hacky.
Are you suggesting something else? track 4 individual moves and then how would you feed them into the player, surely the credit stuff for the moves would be more hassle there than anything.
#3
01/01/2006 (3:02 pm)
Well, you want to have 4 control objects, right?
#4
How does the move manager work? Is it a scripting only change or C+ based change to handle 4 player control objects?
01/01/2006 (6:24 pm)
Ben, How does the move manager work? Is it a scripting only change or C+ based change to handle 4 player control objects?
#5
01/01/2006 (7:06 pm)
It's a class that takes variables that are exposed to script and stuffs them into a Move structure as the client connection(s) demand it. If you look at game/moveManager.cc (I think) you can see the implementation.
#6
So, vehicle physics are generated on both the server and the client and synced with the server?
Does this mean if you have four users on one machine it will generate four times the physics calcs or does it only do it once?
I can't see how adding additional move information would require it, but that would be a concern. I guess by adding move information you are not adding a full blown client, just the info to control another character.
01/02/2006 (12:12 am)
So the move manager Move variable represents all the analog and digital controls sent over the wire? So, vehicle physics are generated on both the server and the client and synced with the server?
Does this mean if you have four users on one machine it will generate four times the physics calcs or does it only do it once?
I can't see how adding additional move information would require it, but that would be a concern. I guess by adding move information you are not adding a full blown client, just the info to control another character.
#7
I had considered making a gameconnection that allowed multiple Control objects, but the move sync and reliance on a single control object logic just seemed like it would be a bad way of doing it.
So now what I do is I accept the move in the player class, and ALWAYS pass it to the AIPlayer class. I altered the AI player class to copy the move into a static "last move" Move struct and I added functions to set the AIPlayers as "slaves", which means that if they are slaves, they get the last move struct and unpack it into an AI move and return it.
It defintiely works, although I fully agree its hacktastic.
SO how would you suggest it be done in a better way? Make the move manager read multiple moves and alter the game connection to allow mutiple control objects, each one getting a move?
01/02/2006 (3:11 am)
Ben. Ive made it work with only a single control object and what IVe called "slave objects" which also get the control objects move packet but then read different parts of it instead of the normal move data inputs.I had considered making a gameconnection that allowed multiple Control objects, but the move sync and reliance on a single control object logic just seemed like it would be a bad way of doing it.
So now what I do is I accept the move in the player class, and ALWAYS pass it to the AIPlayer class. I altered the AI player class to copy the move into a static "last move" Move struct and I added functions to set the AIPlayers as "slaves", which means that if they are slaves, they get the last move struct and unpack it into an AI move and return it.
It defintiely works, although I fully agree its hacktastic.
SO how would you suggest it be done in a better way? Make the move manager read multiple moves and alter the game connection to allow mutiple control objects, each one getting a move?
#8
@Frank - it represents ONLY the inputs. So yes, you would get 8x the processing in a 4 player-on-one-system situation than you would get in a dedicated client situation. Although in that case you could short-circuit the physics and have the client suck its state directly from the server (or have it reuse the collision info or some such). The Player class does this and saves itself a fair amount of collision processing in listen server situations.
Torque is definitely biased towards the client-server case. Sometimes this is a win, and others, not so much. ;)
01/02/2006 (3:38 am)
@Phil - Yes, exactly. Basically stick for-loops around a bunch of cases that are singular now.@Frank - it represents ONLY the inputs. So yes, you would get 8x the processing in a 4 player-on-one-system situation than you would get in a dedicated client situation. Although in that case you could short-circuit the physics and have the client suck its state directly from the server (or have it reuse the collision info or some such). The Player class does this and saves itself a fair amount of collision processing in listen server situations.
Torque is definitely biased towards the client-server case. Sometimes this is a win, and others, not so much. ;)
#9
But again, there is that lovely hard-relation between connections and players and such.
I'll revisit this later when we've got some of the rest of the game complete, as it is Ive got a working solution right now (which wont take much to test out later if I go for another implementation like you suggest).
I'll wriite up the MOVE processing logic into a TND article and see if that helps me/others get a better grasp on the move stuff. Its not THAT bad, apart from the move credit stuff, which just boggles :)
01/02/2006 (4:26 am)
Yeeeash.. ok, yeah, I thought that was a possibility. I also diced with the idea of simply allowing multiple local client connections too, which to me seemed a cleaner method of doing it.But again, there is that lovely hard-relation between connections and players and such.
I'll revisit this later when we've got some of the rest of the game complete, as it is Ive got a working solution right now (which wont take much to test out later if I go for another implementation like you suggest).
I'll wriite up the MOVE processing logic into a TND article and see if that helps me/others get a better grasp on the move stuff. Its not THAT bad, apart from the move credit stuff, which just boggles :)
#10
01/08/2006 (1:35 am)
Would love to see that, thanks Phil. :)
#11
03/28/2006 (6:03 pm)
I am curious about this too, or perhaps there is more about multiple control objects that I haven't been able to find. Can anybody point me in the right direction?
#12
Basically, the move is a engine side struct that gets read by the movemanger to read variables which are script accessible. Every update, the movemanager gets asked to read the current variable states and pack them into a move structure, which then gets sent to the server. Server then gets the connection the move is for and hands it to it.
What I'd done is make the move have 4 parts (one for each AI player in my up-to-four-player game) and when I recieve the move on the server side (when it hands it to the object to handle it) I essentially break it back down into 4 and let each AI object handle thier own part of it, making the AI essentially back into a non-AI player.
As said, its hacky, but the alternative is to find everywhere that the Connection handles control objects and move structures and add an array and index values to it. It turns out that I didnt want to have to deal with that (its the ideal solution, but when I tried to do it, turned up a lot more cases than I wanted to deal with).
Specifically, the move credit stuff seemed a bit unclear and not documented well enough for me to mess with it.
Essentially, right now the default is to have one control object per connection and a lot of the connection class relies on that to be the case.
Phil.
03/29/2006 (4:10 am)
I'll write a TDN thing up next week if I can remember.Basically, the move is a engine side struct that gets read by the movemanger to read variables which are script accessible. Every update, the movemanager gets asked to read the current variable states and pack them into a move structure, which then gets sent to the server. Server then gets the connection the move is for and hands it to it.
What I'd done is make the move have 4 parts (one for each AI player in my up-to-four-player game) and when I recieve the move on the server side (when it hands it to the object to handle it) I essentially break it back down into 4 and let each AI object handle thier own part of it, making the AI essentially back into a non-AI player.
As said, its hacky, but the alternative is to find everywhere that the Connection handles control objects and move structures and add an array and index values to it. It turns out that I didnt want to have to deal with that (its the ideal solution, but when I tried to do it, turned up a lot more cases than I wanted to deal with).
Specifically, the move credit stuff seemed a bit unclear and not documented well enough for me to mess with it.
Essentially, right now the default is to have one control object per connection and a lot of the connection class relies on that to be the case.
Phil.
#13
03/31/2006 (7:23 am)
I got 4 local players working about a month ago. Matt Zuhlke is helping in creating a clean resource out from my code mess, it should be up soon.
#14
I think the move credit stuff is for lag and backlogged movelists (I didn't have to mess with it, but now that I have that out of the way I am quickly forgetting all about it).
I know that since packets are only sent every 32ms, moves have to be stored in a list (mMoveList) until it is time to write a packet, then they are stored in a server- side list until they are processed in GameConnection::pack/unpack update. I tried changing the way they were indexed but it quickly got rather cumbersome and entangled, so I just sent ghost id's before the move information and stored all the move info in the player objects rather than the connection object (the moves are all processed by going through the player list anyway).
I did have to change the control object stuff (it was a pain too).
04/06/2006 (4:22 am)
I ended up just dropping a movelist into player objects to allow for multiple move streams between servers ( I am relaying moves through a server grid). It took a while, and I kept running into a lot of tiny problems that came up, but it was worth the effort, and works fine.I think the move credit stuff is for lag and backlogged movelists (I didn't have to mess with it, but now that I have that out of the way I am quickly forgetting all about it).
I know that since packets are only sent every 32ms, moves have to be stored in a list (mMoveList) until it is time to write a packet, then they are stored in a server- side list until they are processed in GameConnection::pack/unpack update. I tried changing the way they were indexed but it quickly got rather cumbersome and entangled, so I just sent ghost id's before the move information and stored all the move info in the player objects rather than the connection object (the moves are all processed by going through the player list anyway).
I did have to change the control object stuff (it was a pain too).
Associate Kyle Carter
$Player0::mvForward
$Player1::mvForward
etc.
That way you won't run into problems tracking move credits for each player.