Final Draft, October 19, 2002
Technical-Level Connection Process Flow
I've been working on the design and capabilities on the server-side of things. I've been stubbing some stuff out, and I decided to make a flow chart to help me design what I'm going to do. This is essentially the third revision of what work I've been doing internally, so I'm putting it up here for possible comments. Explaination of some concepts are below.
PlayerPacket
The player data is stored in a single packet. I decided on going this route to make things simpler, and for almost all games I can think of, this should be enough. This single packet will allow for approx 500 bytes of data to be attached to the player. You may think "well what if the player has all these units?" My answer to that is that the player data only contains data about the player themselves, for example the player name, player ID, ping time, score, player type (ie in an RPG, this might be a piece of data saying the client wants to join as a warrior or mage), and a few other small attributes. Objects (or avatars) that directly represent players in the game, or the player's units, are best dealt as objects to be handled by the user-side code. Then the packet that described an object in the game also contains the player ID of the person who owns that object. When the packet comes in, the client will create that object, and attach that object to the player using user-defined methods in their subclass of the PlayerData object. In this sense, a single player can have any number of packets "about" that player, but really there is only a single packet that's truly ABOUT the player themselves.
The PlayerData class has virtual methods that ask the user code to create a PlayerPacket describing the player, a method to create a new player based on an incoming packet, and a third method to update a player's information based on a PlayerPacket. The PlayerPacket has a unique ID already assigned by GNE, so the user must always return a single subclass of PlayerPacket and be designed to take that subclass any time GNE asks the user code to use or generate PlayerPackets. The methods here come from the fact that PlayerPacket is a NetworkObject.
Acceptance Process
The client starts out sending its PlayerPacket to the server. The server then decides if it likes that packet or not. If it does, it accepts the client. If it doesn't, it modifies the PlayerPacket and sends it back to the client. It may not like it because the name is not unique (i.e. there is already a player "Jason"), and makes a suggestion (for example to change the name to "Jason2"). If the client sends back the identical packet, then the server accepts the client. If it sends back a different packet, the process starts over. This negotiation is done in the user-side code. The server can choose either to allow the client, suggest a different PlayerPacket, or completely refuse the connection outright and refuse the client (the server also knows its ping times and IP address at this time, and it may decide the ping is too much, or the IP is banned, or something in the PlayerPacket it REALLY doesn't like). This process is done in user-code so that the programmer of the game has the maximum flexibility in handling player data.
Snapshots
A difficult issue in joining players into a game already in progress is snapshotting. When we start sending game state or player information to a new connection, this state will likely change between the time we send the packets (snapshot the current data) and the time the client actually connects. While not conceptually difficult to deal with, it can be a technical problem because from a coding standpoint, a connection transferring the snapshot is connecting, but not connected. You cannot treat it like all other connections, but many of the events for other connections must be queued up for the connecting client.
GNE will handle the issue of snapshotting player's data, but for user-data this is more complicated. GNE will provide a "queue up" method for sending packets after a connection has completed. The idea behind the queuing is this:
The user will be responsible for ensuring the game logic synchronization. One possible user-code solution to the problem:
Because the event thread remains open during the snapshot process, the user code can decide if and when the connecting client times out because it views it as too slow.