일만 하고 휴식을 모르는 사람은 브레이크가 없는 자동차 같아서 위험하기 짝이 없다. 또한 일할 줄 을 모르는 사람은 모터가 없는 자동차 같아서 아무 소용이 없다. -존 포드
* 원본 링크 :
http://www.gdse.com/articles/multifaq.txt
http://www.gdse.com/articles/multifaq.txt
From: "Kali, Inc. Information" <INFO@KALI.NET> Organization: Kali, Inc. Date sent: Fri, 2 Jan 1998 16:03:49 EST
Mutliplayer Game Writer's FAQ
Version 0.9
(c)Copyright 1996 by Kali, Inc.
All Rights Reserved
Written by Jay Cotton
Copyright Notice #
This document is Copyrighted 1996 by Kali, Inc.
You may make copies of this file and provide this text to anyone wanting to know more about writing games that work better over the internet, but you must include this entire text without any changes. You may not copy any part of this document without prior written consent from Kali, Inc.
Writer's Note #
This is just a beginning. There is a ton of information that can be included in this text, but it will take quite awhile to gather everything together. If you have anything to contribute please contact Kali by sending email to jay@kali.net.
What's Included in this Document #
Not much yet. Just some basics on how to layout your network communications. We have not added any IPX or TCP/IP specific information yet. Everything in this document applies to either system. So far we're just explaining why some games work better over Kali.
Getting players connected #
Generally you should not write applications that depend on the use of broadcast packets for anything except finding other nodes that are already running the game. Any existing nodes should respond to the broadcast packets by directing a packet to the sending node. After this exchange is made both nodes know the address of the other. There is no longer a need to send any broadcast packets. Any new nodes will send a broadcast that all of the existing nodes can respond to. Because packets might be lost never assume that one broadcast packet will reach every node. It might be necessary for each node to compare lists when connecting to be sure they agree on who's present. Each node is responsible for maintaining their own list of nodes.
One system that works is to have a new node broadcast a message to see who is present already. In the event that no other nodes are present this node should continue to send a broadcast every 2 seconds while also listening for other broadcasts. Any node that receives a broadcast message should reply to the sender with a message indicating that they are present and also provide a list of other nodes already in that user's list. This way even if the new node doesn't get a response from all existing nodes, he'll still have a complete list as reported by one of the existing nodes. In order to assure that each existing node is aware of the newcomers the new node must direct a message to any node that is on his list (the list built from the responses to the broadcast packet) to say "I'm here!". He must also make a reasonable effort to contact this other node.
Resending a packet every 2 seconds for 20 seconds before giving up and assuming the other node is dead.
You don't have to get this complicated, but this is the only way to ensure that a set of players remains intact even if any of them disconnect without notice.
A simpler model, and the one used by most games is to have nodes specified as either hosts or clients. A host doesn't send any broadcasts, but rather creates a game and waits for others to join. As nodes join he adds each node's address to his list and then polls these addresses on a regular bases to make sure they haven't disconnected
unexpectedly. A player trying to join will broadcast packets asking for games. All current hosts will respond with game information. The person joining then gets a list of all current games and can choose one. He continues to re-broadcast every 2 seconds or so until either exiting or choosing a game. Upon choosing a game he sends a packet requesting permission to join directly to the node that offered the game. From then on all packets are directed. When the game launches all nodes can still
be considered peers, but the host will be responsible for providing the initial game startup information (including the list of nodes).
Lessons to learn from other games #
Descent is unsynchronized. Basically each node just plays at full speed and sends packets about 5-10 times per second to indicate position. When weapons are fired, objects are picked up, or a collision occurs an extra packet is sent which includes this info.
Each node listens for packets from other players and when packets are dropped or late it makes a guess as to where they are based on their last location and trajectory. Descent will continue to guess at locations for up to 4 seconds. Each node keeps track of his own version of the game.
Because of this guesswork each player might actually see different objects and different scores. Sometimes two people are able to pick up the same object which tends to cause weapons to build up until there are lots of extras lying around. Recent changes to the code fix it so that each PC knows where each object is supposed to be available and it will reduce the number of available weapons when too many appear.
Warcraft 2 is totally different. It's a synchronized game. This insures that all players see the same thing and that all scores match exactly. To allow this to work and still run fast over the internet they delay actions by a value which can be set by the user on the command line.
With War2 there is a commandline option to adjust a delay for the other nodes to have time to respond. When increased, War2 will do something like this:
- The game runs on all nodes at full speed. Packets are sent at a regular interval to make sure everyone is still connected. There is data in the packets, but echnically until a user issues an order there is no need to send any real data. Just a frame number and possibly a time stamp that can be sent and returned for adjusting for lag. This packet can also contain a value that indicates the last command received from the remote node. This way the remote node will know everyone received his command without having to issue an extra ack (acknowledgement) packet.
- The user commands a grunt to move. We're talking about the final command to move...not just the first click to select the Grunt or the scanning of the map for grunts.
- War2 immediately sends a copy of the command to all nodes and then places this command in a "command buffer". Basically just a list of commands to be executed and a time stamp or frame stamp to indicate when the command was issued or when it's supposed to be executed.
- The packet sent will contain the command and the time or frame stamp so that all nodes will know when to execute this command. Basically each packet that is sent will contain the information on what to do at each future frame. Each packet can also contain the number of commands that have been issued so far so that if one packet is lost, and the next packet arrives indicating that the number of commands has not increased the receiving node will just ignore the lost packet and continue normally. If data is missing, it can set information in it's own packet to that remote node to indicate which commands are missing.
By letting the remote node know right away that a command needed is missing delays can be minimized (better than waiting until time to issue the command and then asking for the data again).
- When a node gets a command from another user it adds this command to the command buffer just like it places it's own commands. It also sets the last command received information in the next packet it sends to the user that sent the command.
- At each frame the game checks the command buffer to see what needs to be executed during this frame. If the command information for all users is not available it will continue to send the same packet to the other nodes until it receives all of the information. For remote nodes that you need data from your packet will contain the range of missing commands (like previous packets already contained) and for other nodes you just send a packet that basically states your waiting on someone else.
Duke vs. War2 #
Duke Nukem seems to guess at the lag between nodes and adjusts a delay like War2. Quite a nice idea, and it mostly works very well. Being able to auto-adjust means that LAN games seem to run more like Doom. It's not exactly the same, but close. With Doom you KNOW what you're shooting. With Duke it's still a small guess (but still synched).
There is a problem though. Apparently the game runs out of room to store actions and you'll find your gun has stopped firing. If you don't let off and let the game catch up it eventually goes out of sync.
I suspect this could happen in War2 also, but the game is such that you don't have to send rapid- fire packets that can quickly overload a buffer. I also think War2 actually stops when it runs into trouble like this. Duke Nukem keeps running full speed until it dies. I think I would prefer to slow down for just a second or two.
More #
Actually, I've added a few extra items to the scenario above that improves slightly on the War2 model. One further improvement, that can be made would be to have the game itself try to determine the lag and adjust the command delay automatically. It could start with the delay specified on the command line and then adjust up or down based on the average time it takes to get the acknowledgement of each packet. Using a little statistics you can calculate the average and standard deviation and set the delay to
handle 95% of the response times. Of course you can put limits on the range that it tries to use, but if it really does take 1000ms to get a response then using anything less would cause lots of problems.
This system takes care of several problems that are faced on the internet:
- Bandwidth: By only including command information in packets when the commands are issued the normal packet will be very small. Your application already does this so you should be ok here. Reducing bandwidth requirements also helps lag and packet loss. If too much data needs to be sent the game either has to slow down or data has
to be dropped.
- Lag: By not requiring immediate confirmation or trying to synchronize every frame you can basically work with ANY amount of lag. The penalty is the slight delay between issuing a command and seeing the command executed. Not all games would work as well with this delay, but in this type of game players would rather these delays as long as the normal execution of the game is full speed (the construction moves along at full speed). The only time the game will slow down is if data is either lost and the resend doesn't occur before time to execute the command or the delay is not set long enough (thus causing unnecessary resends).
- Loss: Even if lots of non-command packets are lost the game will not slow down. No re-sends are necessary except for packets containing commands. As a result we also reduce bandwidth (which in turn helps lag and loss...which is good...
- Sequencing: getting data out of order is not a problem since each command contains a framing number to indicate when it needs to be executed. Old data might arrive after replacement data has already been sent. No problem...just drop the redundant information. Even if a command for frame 10 arrives before the command for frame 9 the data for 9 might be re-sent, but the data for frame 10 is not lost since it's already added to the buffer.
To improve the handling of lost information, you might allow for backup information to be stored in packets. In the simplest case you might have each packet contain the current information along with a copy of the last bit of information. If one packet is lost, the next packet will contain the missing data. In a setup like Descent this would not help since lost information isn't important and the added packet size would decrease performance. In the case of Doom2, this can actually be adjusted to have
each packet contain as much backup data as you want.
If you were sending action info (to be accomplished on a certain frame) you would normally have to wait until that frame to know if it was sent. If the next packet that went out also included this information (as a backup) the response might arrive late (thus causing a resend), but the response from the second packet might arrive soon after (the response isn't an extra packet, but rather just acknowledgement in one of the regular packets that the next action item had been received). In this case instead of a 300-500ms delay while waiting on acknowledgement of the resend, we would actually be able to continue the game almost right away since the next packet from the other node would have acknowledged the backup data.
Doing this properly will allow you to avoid those occasional and sometimes very annoying pauses that occur in War2 and C&C. With this option set properly I can play Doom2 over a bad connection with almost no pauses, but of course it's still somewhat slow.
Just combine all the best ingredients from these other games and you'll have a game that runs fast and plays smooth.
One last item to consider. Bandwidth. Keeping the number of packets and size of packets to a minimum is a must. If you run out of bandwidth on your connection everything will slow down. Allowing a users to reduce the number of packets sent per second can help a lot. Compressing or removing unnecessary data from packets will help.
Even in a 2 player game where you might not have a bandwidth problem, you would still want to use smaller packets simply because they travel faster across the modem. It just takes longer to send a 150 byte packet than it does a 15 byte packet. Just don't add more packets in your effort to reduce packet size. It will take longer to send two 15 byte packets than it will take to send one 50 byte packet because of the overhead on each packet.
..more to come someday...








