fast-action multiplayer internet games
I''m trying to find more info on designing the game object hierarchy for fast-action internet games. Can anybody help with that? I''ve read all the articles here and at Gamasutra, but there''s only general info on the topic. And i want more about implementation techniques. I would be glad for every link and post. Thanks in advance.
hmm... what i mean is: i need info on managing game objects, network events (game messages, connection requests, disconnection events), setting up the game loop, building a prediction system, etc...
Hey,
This is a very complicated topic so I guess that''s why you haven''t had any responses yet. I am by no means an expert on the subject, but I''ll ramble a bit and see what I can get across to you.
The first thing to know is that if you''re doing a multiplayer game is to do the multiplayer at the beginning. It''s not just something you add in at the end to top off your finished product--your entire game structure has to be planned around it. I''m glad I realised this before I got too far into the project of my own.
Ok, so on to my ramblings. I''m going to assume you''re using a client/server methodology to implement your game simply because it''s the easiest to explain.
The most basic part of multiplayer game programming is to get your head rapped around the fact that the client program doesn''t do all that much except what the server says is ok. It''s much like a game of "Mother may I?" The client is the server''s interface to the user--the user says (by pushing a key, or moving the mouse, or yelling loudly enough) to the client, "Hey, I want my character to move forward!" And the client sends out a request to the server saying "Yo, Server, is this ok?" The server then makes the decision if it is ok for the client to move there or not. If it is, the client moves. If not, it doesn''t easy as that.
On top of validating user actions the server has to send the client stuff for the user to interact with. If a monster (our local "Giant Electric Pink Fish Named Fred") is running over the hill to attack the user (as determined by the server) then the server sends out a message to the client telling it to spawn Fred and give him an action state--running toward/attacking the player.
Now to some code theory about all this. The client has to implement a system to send/recieve messages to/from the server. I personally use a nonblocking listener that sends a message to a user-defined function that processes the message. My standard message format is 54 bytes in size, maximum. I intend to trim it a lot, but this is what it looks like:
LOWORD of "Message" holds the message''s command number, and its HIWORD is the number of parameters that were passed. The more interesting part is next, the union. Because a DWORD and a FLOAT are equal in size, they take up the same space and you can store data of both types inside the union. This will make more sense in a second.
Say you have a command called "Spawn_Monster." It''s command number is 100. The server is sending this message to a client telling it to spawn a troll at position -100, 0, 100. The symbol "troll" will parse to, say 5000. The final command when it''s passed from server to client will be:
100 5000 -100 0 100
Now obviously we have a problem here. What happens if you want to pass a different function with different parameter types? That''s where the union comes in.
Ok so on to managing game objects. First of all, "managing game objects" is a slight misnomer because the objects all need to be able to manage themselves on client-side, being as the server can tell it to create/destroy many of them all the time and the client doesn''t have any control over that. I suggest each object be able to be easily created, rendered, updated, and destroyed. It needs an individual index too for that matter--that way the client can maintain a list of objects in the game and say "hey, object 12345678 was picked up by a player, stop rendering it." The way I do it is...
As you can see, I''m fond of unions.
In this case it isn''t strictly necessary too much, but it prevents redundant typecasting needed using a void* pointer. This union points to a new-ed object of the chosen type, whose symbol number is stored in Type for future reference. The Index is the server''s index number for this object. The most complicated thing about this part is implementing a list to manage the objects. I suggest using a SPAM structure. What''s that you ask? It''s another paper in itself
You won''t find it on the net though, because "Specific Purpose Allocatable Memory" is my own creation. Basically it''s a quick way to allocate memory you need for only one structure.
As you can tell I''m kinda going about this erratically, but if you''ve made it this far I commend you!
The game loop is probably the hardest thing about the game engine. You have to be able to manage different functions without the need for an "if" statmenet for each one. For example, you want to avoid...
That''s really what you DON''T want. Try to make a hierarchial structure where one command leads to another, and if a higher-level command isn''t called then it won''t call its subcommand either. Much like a quadtree.
The last thing you mentioned that I can answer is a prediction system. By this, I assume you mean dead-reckoning where players are because the server hasn''t told you recently. This is probably one of the easiest things to do. All you do is store its last known "state" with its data. The state usually is something such as "idle", "walking", "running", "casting a spell", "attacking", etc. Each state has data associated with it. Walking would store the object''s position, angle and speed. Same for walking, but has different animation data. Casting a spell might store what spell was being cast, etc.
If you''ve made it through all this, I think you can tell that handling connect/disconnect requests is the least of your problems
They''re really simple though, especially with a server-client method. Look up the winsock "Non-Blocking Server" code here on GameDev for more info about the implementation...it''s lunchtime and all this typing made me hungry!
Good luck with your endeavours,
Karl
This is a very complicated topic so I guess that''s why you haven''t had any responses yet. I am by no means an expert on the subject, but I''ll ramble a bit and see what I can get across to you.
The first thing to know is that if you''re doing a multiplayer game is to do the multiplayer at the beginning. It''s not just something you add in at the end to top off your finished product--your entire game structure has to be planned around it. I''m glad I realised this before I got too far into the project of my own.
Ok, so on to my ramblings. I''m going to assume you''re using a client/server methodology to implement your game simply because it''s the easiest to explain.
The most basic part of multiplayer game programming is to get your head rapped around the fact that the client program doesn''t do all that much except what the server says is ok. It''s much like a game of "Mother may I?" The client is the server''s interface to the user--the user says (by pushing a key, or moving the mouse, or yelling loudly enough) to the client, "Hey, I want my character to move forward!" And the client sends out a request to the server saying "Yo, Server, is this ok?" The server then makes the decision if it is ok for the client to move there or not. If it is, the client moves. If not, it doesn''t easy as that.
On top of validating user actions the server has to send the client stuff for the user to interact with. If a monster (our local "Giant Electric Pink Fish Named Fred") is running over the hill to attack the user (as determined by the server) then the server sends out a message to the client telling it to spawn Fred and give him an action state--running toward/attacking the player.
Now to some code theory about all this. The client has to implement a system to send/recieve messages to/from the server. I personally use a nonblocking listener that sends a message to a user-defined function that processes the message. My standard message format is 54 bytes in size, maximum. I intend to trim it a lot, but this is what it looks like:
struct MSGTYPE{ DWORD Message union { DWORD Cmd; FLOAT Num; } Param[8];};
LOWORD of "Message" holds the message''s command number, and its HIWORD is the number of parameters that were passed. The more interesting part is next, the union. Because a DWORD and a FLOAT are equal in size, they take up the same space and you can store data of both types inside the union. This will make more sense in a second.
Say you have a command called "Spawn_Monster." It''s command number is 100. The server is sending this message to a client telling it to spawn a troll at position -100, 0, 100. The symbol "troll" will parse to, say 5000. The final command when it''s passed from server to client will be:
100 5000 -100 0 100
Now obviously we have a problem here. What happens if you want to pass a different function with different parameter types? That''s where the union comes in.
Ok so on to managing game objects. First of all, "managing game objects" is a slight misnomer because the objects all need to be able to manage themselves on client-side, being as the server can tell it to create/destroy many of them all the time and the client doesn''t have any control over that. I suggest each object be able to be easily created, rendered, updated, and destroyed. It needs an individual index too for that matter--that way the client can maintain a list of objects in the game and say "hey, object 12345678 was picked up by a player, stop rendering it." The way I do it is...
struct Object{ DWORD Type; DWORD Index; union { BoxObject * Box; GunObject * Gun; PlayerObject * Player; FredObject * Fred; FlashyDaggerObject * FlashyDagger; } Obj;};
As you can see, I''m fond of unions.
![](smile.gif)
![](smile.gif)
As you can tell I''m kinda going about this erratically, but if you''ve made it this far I commend you!
The game loop is probably the hardest thing about the game engine. You have to be able to manage different functions without the need for an "if" statmenet for each one. For example, you want to avoid...
...while(true){ if( bRenderingMenu ) RenderMenu(); if( bDrawOverheadMap ) DrawOverheadMap(); if( bTimeToQuit ) break; if( framecount == 0 ) UpdateFrame(); // etc.}...
That''s really what you DON''T want. Try to make a hierarchial structure where one command leads to another, and if a higher-level command isn''t called then it won''t call its subcommand either. Much like a quadtree.
The last thing you mentioned that I can answer is a prediction system. By this, I assume you mean dead-reckoning where players are because the server hasn''t told you recently. This is probably one of the easiest things to do. All you do is store its last known "state" with its data. The state usually is something such as "idle", "walking", "running", "casting a spell", "attacking", etc. Each state has data associated with it. Walking would store the object''s position, angle and speed. Same for walking, but has different animation data. Casting a spell might store what spell was being cast, etc.
If you''ve made it through all this, I think you can tell that handling connect/disconnect requests is the least of your problems
![](smile.gif)
Good luck with your endeavours,
Karl
Hey, Karl G, i already know all that. I''m using asynchronous sockets under Windows, and non-blocking (select()) sockets under linux. I have already created the messaging system (c++ pluggable factories are implemented to help adding new messages and extending the system). My networking lib, can nadle both TCP (with partial send/recv handling) and UDP (with a kind of RDP implementation of my own, just to get sure all the actual data is sent and received). Now i got some troubles with the game logic.
First of all, troubles when handling disconnects... I mean the server should notify clients that someone has disconnected, so that each player had a real game situation locally. And imagine the player has performed a shot (from a grenade launcher or another weapon), and the grenade kills some players. Now we have to increment the frag counter for the player, who performed the shot. But what if he had disconected while the grenade was in the air? The grenade has a pointer to its parent object... and when the object is deleted, we get a segfault, when trying to access the deleted player frag counter.
Next comes the lag fighting. How do i build a good-quality prediction system (at least as it is in quake2/counter-strike)? There''s a lot of theoretical info on this topic, but nothing concrete...
There are many other question, but these two are tho most important for me at the moment.
First of all, troubles when handling disconnects... I mean the server should notify clients that someone has disconnected, so that each player had a real game situation locally. And imagine the player has performed a shot (from a grenade launcher or another weapon), and the grenade kills some players. Now we have to increment the frag counter for the player, who performed the shot. But what if he had disconected while the grenade was in the air? The grenade has a pointer to its parent object... and when the object is deleted, we get a segfault, when trying to access the deleted player frag counter.
Next comes the lag fighting. How do i build a good-quality prediction system (at least as it is in quake2/counter-strike)? There''s a lot of theoretical info on this topic, but nothing concrete...
There are many other question, but these two are tho most important for me at the moment.
For the "grenade''s owner leaves"
you can either make the grenade be owned by the world container object (in which case the "world gets the kill"...), or you can set the owner pointer to null when the player leaves and just not give anyone kills... or you can simply delete the grenade as well.
In star control 2, there were spaceship duels. Some ships could launch a projectile that would stick around until they died (and then suddenly disappear with the parent) -- sure, it''s unbelievable, but I don''t think anyone would care that much if the object was deleted.
you can either make the grenade be owned by the world container object (in which case the "world gets the kill"...), or you can set the owner pointer to null when the player leaves and just not give anyone kills... or you can simply delete the grenade as well.
In star control 2, there were spaceship duels. Some ships could launch a projectile that would stick around until they died (and then suddenly disappear with the parent) -- sure, it''s unbelievable, but I don''t think anyone would care that much if the object was deleted.
well, the grenade was just an example... there are amny complex issues, events and situations when handling disconnections can kill the game loop...
The best thing I''ve found to do is just NULL out any pointers and set any data to an invalid value (such as -1234.4321 for floats, or 1234567 for DWORDs) and have the loop check for invalid data and discard it when it comes across it.
It is easy for the client to guess wher an object should be in the next frame. Just use the acceleration and speed which can be calculated or transmitted by the server.
That''s what i have done in the game at http://www.hublot.org
(to play, just enter your name and click on the character you want, without typing ''enter'' key)
If you want some details, just mail me : hublot_contact@yahoo.fr
bye,
Lexa.
That''s what i have done in the game at http://www.hublot.org
(to play, just enter your name and click on the character you want, without typing ''enter'' key)
If you want some details, just mail me : hublot_contact@yahoo.fr
bye,
Lexa.
Yo!
A common method within multiplayer games is to use handles which point to an object which spans the network. Since the objects states is usually unpredictable, whenever you resolve an object handle -> object ptr this usually locks it. That is, it maintains a refrence count as well as places a lock on an object thread wise, to prevent other threads from modifying its internal propertites while ur using the object or the object being deleted while u work with it.
The code should handle failed attempts to resovle the object ptr. Also the handles are consistent within the network, so on machine A and B a handle will resovle to the same object.
Another common technqiue is to use a reduced object representation on the client side vs the server side. An object on the server side could contain addtional data and functionlity, which doesnt exist on the client side. The objects then synchonize each others states, through a state sync packet, which allows you to offload critical processing on the server side while keeping the client relaltively thin.
For a fast paced action game, there are 2 main overiding networking issuse, latency and accuracy.
Look into time sync algorithims such as NTP. This will allow you to get the game clocks to within 10 ms usually. Once u have this, the next part is to paramtrize all ur movement functions into representations in which u can use this time paramter as the main input. This will syncrhonize ur movement functions to the accuracy of the timmer, which is very high.
There are many networking models, however for fast action games, i suggest using a multi threaded approach in conjunction with a pool of worker threads. This will allow u to async handle clients from ur main loop, which prevents the annoying problem of people with slow connections stalling the server. The worker threads reduce the overhead of starting and stoping threads, as well as the number of threads needed in general to serivce ur clients.
Client side prediction and authoritive events, need to be carefully weighted with respect to cheating. If ur client is too authoritve it will be exploited. So thats really a grey area, and u can decide how much the client can do, and how much it has to request from the server.
Well Good Luck!
-ddn
The code should handle failed attempts to resovle the object ptr. Also the handles are consistent within the network, so on machine A and B a handle will resovle to the same object.
Another common technqiue is to use a reduced object representation on the client side vs the server side. An object on the server side could contain addtional data and functionlity, which doesnt exist on the client side. The objects then synchonize each others states, through a state sync packet, which allows you to offload critical processing on the server side while keeping the client relaltively thin.
For a fast paced action game, there are 2 main overiding networking issuse, latency and accuracy.
Look into time sync algorithims such as NTP. This will allow you to get the game clocks to within 10 ms usually. Once u have this, the next part is to paramtrize all ur movement functions into representations in which u can use this time paramter as the main input. This will syncrhonize ur movement functions to the accuracy of the timmer, which is very high.
There are many networking models, however for fast action games, i suggest using a multi threaded approach in conjunction with a pool of worker threads. This will allow u to async handle clients from ur main loop, which prevents the annoying problem of people with slow connections stalling the server. The worker threads reduce the overhead of starting and stoping threads, as well as the number of threads needed in general to serivce ur clients.
Client side prediction and authoritive events, need to be carefully weighted with respect to cheating. If ur client is too authoritve it will be exploited. So thats really a grey area, and u can decide how much the client can do, and how much it has to request from the server.
Well Good Luck!
-ddn
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement