This code explanation is intended to be used with the NetPlay Minimum Application and my opinion of what the Genesis3D NetPlay API Function Reference will look like. Please keep in mind that my opinion of how Genesis Netplay works may well be wrong. However, while the NetPlay Minimum Application is not rock solid programming, it does work and I hope that you will be able to learn something from it.
The code can be divided into five major sections: Global Variables, The Frame Loop, the Window Message handler, the Text routines, and the NetPlay code.
Global Variables:
The important variables here are TextEntryMode, ChatMode, IPEntryMode, NameEntryMode, ClientMode, ServerMode and clients. The TextEntryMode lets the rest of the code know that the keyboard is now being used for some kind text entry as opposed to command-key entry. ChatMode simply specifies that the text being entered is to be transmitted over the network as a chat message. IPEntryMode is used to indicate that the text being gathered is an IP address that is to be used to connect to a server. NameEntry mode indicates that the text being gathered will be used as the in-game name. ClientMode causes the program to behave as a client when true. ServerMode causes the code to act as a server when true. "clients" is an array of pointers to geCSNetMgr_NetClient structs. As clients connect to a server, the server will store pointers to the clients’ respective geCSNetMgr_NetClient objects in this array.
The Frame Loop:
The frame loop is pretty much the same as the original minapp code. The movement code in MoveCamera is slightly better. More importantly though are the four new functions: TextEntry, TextPump, ClientCycle, and ServerCycle, that are called each frame. (They may not do something every frame, but they have the opportunity to do so.)
The Text Routines:
The TextPump simply displays an array of strings at the top of the screen. Every so many seconds the top most line
expires and the other lines are all shifted up. You can add strings to the textpump’s display array with AddDisplayString.
TextEntry works with the Window Message handler to gather text input from the user. For example: pressing the ‘C’
key will set the IPEntryMode var, and the TextEntry Mode var to TRUE. This will cause the window handler to stop
interpreting the keys as commands and instead load all subsequent characters into a global buffer that is displayed
near the bottom of the screen as the user types them. When the user presses the return key the message handler
will set TextEntryMode to false. In the case of an IP address this high to low transition will cause TextEntry
to pass the entered IP address to the ClientConnect routine in the NetPlay code. In the case of a chat message,
TextEntry will send the completed string to the server with the SendChatToServer routine.
The NetPlay Code:
StartServer – This function simply calls the two Genesis API routines necessary to start a server. ge_CSNetMgr_Create is a call that generally gets the NetPlay portion of the API up an running. It does not specifically create a server or a client though. Calling this function is analogous to calling ge_EngineCreate. You have to call geCSNetMgr_Create before you can call any other netplay functions, but calling it once is enough. geCSNetMgr_StartSession is the call that actually starts the server. It is important to realize that it also creates one client for the machine it is running on and automatically causes that client to join the session. You can only create one server per a program, and likely one per a machine.
The rest of StartSever is dedicated to status messages and the ServerMode global variable.
StopNetPlay – This function will just call the one or two API functions required to deactivate Netplay depending on whether or not it is server. geCSNetMgr_StopSession will destroy the server.
ClientConnect – This code will call the three API functions necessary to become a client of a server. geCSNetMgr_FindSession is called with the IPAddress that the user was prompted to enter when he hit the ‘C’ key. geCSNetMgr_JoinSession is called to make this program a client of the server. Note that the Name the client entered gets passed to the server here. If all goes well here, the program will become a network client and the global var ClientMode will be set true to indicate that.
ClientCycle – This routine is called each frame by both server mode programs and client mode programs. It does the receiving for all clients, even the server’s local autoclient. geCSNetMgr_RecieveFromServer keeps getting called until it returns false, indicating there are no more MSG’s from the server.
For each true _ReceiveFromServer call, that got a message of type NET_MSG_USER, the very first byte of data is "switch"’ed on to determine the message’s sub-type. Sub-types are something I defined and are not enforced by the API. For my program I decided that the very first byte of all of my messages would be used to indicate what (sub)type of message I am sending (I originally meant to have several sub-types for this program, but the code started getting too big for it’s britches.) If the message is SUBTYPE_CHAT then, per my definition, the chat message itself is known to start at the second byte and continue to the end of the message and will include a null-termination. ClientCycle will extract the chat portion of the message and display it on the user’s screen. Whether the program is a client or a server, ClientCycle is the only place a chat message actually gets printed to the user’s screen.
SendChatToServer – This function builds a SUBTYPE_CHAT message in accordance with my definitions of what net messages should look like. It then transmits that message to the server using geCSNetMgr_SendToServer. SendChatToServer is called by TextEntry with whatever string the user typed after hitting the ‘T’ command key. It is important to realize that the string the user type is not displayed on the user’s screen. Only chat messages that are received from the server will be displayed on the clients screen in this program. Thus, the clients’ users only see their own chat messages after the server repeats it back to them and they receive it in ClientCycle.
ServerCycle – If you are a server, this routine is called every frame.
Similar to ClientCycle the geCSNetMgr_ReceiveFromClient API call will keep getting called until the function returns false indicating we have processed all the messages in the receive buffers. (Note that a copy of the returned message data is made. This is important since we are going to call several Net API functions and pass that data soon.)
Also similar to ClientCycle, if the received message is a NET_MSG_USER message, ServerCycle will "switch" on the first byte of the message to determine what sub-type it is. (Again there’s only one sub-type but the mechanism used could be expanded to support 256 sub-types) If the Message is SUBTYPE_CHAT the global array of clients (a structure that is built by the code in the next paragraph) is scanned to match up the cId value that was returned by the receive function with the Id value of one of the clients in the array. That client’s name is then pre-pended to the text of the chat message and the chat message is sent back to the same client. But, since sending to one client means sending to them all, every client will see the chat message.
If the message is a NET_MSG_CLIENT_CREATE then the global array of clients will be scanned for the first available slot and the contents of the message will be copied to that slot. The contents of a NET_MSG_CLIENT_CREATE message is always the geCSNetMgr_NetClient struct for the client that just joined the session. Note that this works even with the server’s local autoclient.
If the message is a NET_MSG_DESTROY_CLIENT the global array of clients will be scanned until the _NetID from the message is matched to a particular client slot. That slot will be freed up.
It is important to realize that ServerCycle does not put any chat received messages into the TextPump. It simply pre-pends the Name of the sending client and repeats the message back out to all the clients, including the server’s own autoclient.
SendChatToClient – this function is very similar
to SendChatToServer except that it takes the NetClient struct as an argument in order to specify which client you
would like the chat message to go to. In practice, though, it does not matter which client you specify; a single
call to geCSNetMgr_SendToClient will result in a transmission to every client, regardless of the client specified.