GNE -- Game Networking Engine

0.75.0

See the Readme file and the specific readme for your compiler (ie readme.vc for MSVC) for requirements and installation instructions.

Table Of Contents

Beginner's Guide to GNE

Last updated 9-1-2003.

This section has some information that will help you get started with using GNE. The purpose of this guide is not to teach you everything about GNE but instead as overview to understand the basics of how GNE works and to point you to the examples and documentation to learn to code for GNE.

There is now available a new GNE tutorial for making GNE programs, meant for the beginning user. You can find it in the docs package or on the GNE website. Originally this beginner's guide was the only help for GNE, so the tutorial overlaps this guide. However, the tutorial goes in depth and explains the code, whereas this guide is a general outline of the library.

Do not forget that there are lots of examples and tests in the examples directory. After reading this guide you'll probably want to examine the examples to see some sample code. exaddr, expacket, and exhello are good examples to look at first. The example expong is the first example game using GNE and shows the basics of how to create a framework for a GNE game.

There are several parts and services that the GNE library provides.

Throughout this guide, there will be classes marked with a star (*). These classes are ones that you probably could not make program without using them, and you'll probably want to learn them first.

Classes that are not listed are ones that are used mostly by GNE itself and you'll probably not need to use them directly in normal circumstances.

Table Of Contents

Base API

The GNE namespace contains the functions you need to initialize GNE and miscellaneous functions to interact with the library. The base API also consists of the classes:

Table Of Contents

Threading API

The following classes are in the threading API.

Threads are used throughout GNE. You will need a basic understanding of threads to use GNE. You won't need to create any threads yourself, but you receive events in different threads from your game engine, so you will need to understand when to use mutexes to guard your game engine's data.

For those of you who have used Allegro, the Allegro timers and their callbacks are done in threads, and so are GNE's timers and events.

Basically, what a mutex does is it only allows one thread into a section of code at a time. You should use a mutex around a section of code that accesses any data on the heap (ie static variables or allocated using new or malloc) that is shared by more than one thread.

For more information a link to a pthreads tutorial: http://www.llnl.gov/computing/tutorials/workshops/workshop/pthreads/MAIN.html

GNE uses pthreads internally. You can pick up on threading concepts and examples in this tutorial although obviously the functions don't apply as you should use the threading classes. You'll want to focus espically on the area of detaching, joining, and mutexes. After you read that check the documentation for the GNE classes to see the differences.

Table Of Contents

Console API

The following things are in the Console API:

Standard C/C++ only allows for line buffered input and output. It does not allow for output the same time as input, nor does it allow the user to get input without the user pressing enter or reposition the cursor. These features are useful for game servers so that one can implement a console where the user can input/chat while other messages are being outputted. Additionally, the standard C/C++ I/O is not thread-safe.

GNE provides multithreaded console I/O which you can use to make text-based servers, consoles, or chat programs. See the exinput example for sample code using the GNE Console API, although every GNE example makes use of the GNE Console API.

Table Of Contents

Core Connection API

This is the heart of GNE. The Connection API consists of:

The Connection API provides the classes to send data between computers. Connections in GNE handle bandwith controls, do version and error checking, parse packets, and more.

Learning this part of GNE can be a little confusing at first as to what classes to use and when you use them. The exhello example shows the minimum proper code to set up your connections.

Connection is the base class of every GNE connection. While you won't directly create an object of type Connection, you will use the methods of this class, and espically the PacketStream that it contains.

Connections generate events and send them to a ConnectionListener. You will need to create your own ConnectionListener and a large part of your networking logic will be in this class. The ConnectionListener is what actually makes the connection do anything useful.

When you are ready to make a connection, you will need on the server side your own ServerConnectionListener to listen for incoming connections, and of course a ConnectionListener to provide the actual server's functionality.

On the client side you will use a ClientConnection and a ConnectionListener to connect to this server.

The PacketStream represents an outgoing and an incoming queue of packets. To get sent packets, use GNE::PacketStream::getNextPacket or GNE::PacketStream::getNextPacketSp to receive the next incoming packet. Use GNE::PacketStream::writePacket to send one.

PacketStreams can also be tied with a GNE::PacketFeeder. A PacketFeeder provides a way to feed a continuous stream of packets that is based on the bandwidth of the connection. For example if you wanted your client to send update packets as fast as it can, but you always want to send the latest information, what you would do is create a packet, send it, wait for it to be sent (based on the bandwidth of the connection), and then repeat again. In GNE a PacketFeeder provides this sort of functionality.

To send and receive packets, you will want to derive your own packet class from GNE::Packet and register it with GNE::PacketParser::defaultRegisterPacket. Override all of the relevant functions in Packet and in the writePacket and readPacket functions will be the only place you are likely to use the GNE::Buffer class. The Buffer represents the serialized form of a packet. Use it similarly to an fstream. Seeing the exhello example is probably the best way to learn how to make your own packets.

Once you make your own packet types and register them, GNE will be able to recognize and parse these packets and be able to send and receive them through the PacketStream as it would any other packet. You can use the GNE::PacketParser methods GNE::PacketParser::createPacket, GNE::PacketParser::clonePacket, and GNE::PacketParser::destroyPacket to create and manipulate packets registered with GNE. The system allows for advanced users to provide custom memory managers if needed to allocate the packets.

You only have to use SyncConnection when connecting, and even then, only if you want to negotiate a new connection using a blocking (rather than event-driven) format. But the SyncConnection is a helpful class to write connecting code or to do connections where you are sending a packet and are waiting for a specific response packet. See the exsynchello example for a version of exhello using SyncConnections rather than the PacketStream, and further note that exhello and exsynchello are completely compatable with each other -- so they are doing the SAME thing over the network but are simply just two ways of doing it.

Shutting Down

GNE will help you handle connections, threads, and timers when it shuts down by gracefully disconnecting all connections (as if you had called disconnect on them), calling shutDown on all threads (which you see as a flag being set to true), and stopping all active timers. GNE internally keeps a list of all of these active resources so they are shut down at program exit (as part of the atexit routine), or when you explicitly call GNE::shutdownGNE.

By default GNE will wait up to ten seconds for all threads to terminate, after that time the process will be forcefully closed without a proper shutdown. On some operating systems when GNE is compiled as debugging mode you will see an assertion failure "assert( !isRunning() );" in Thread.cpp if the process is forcefully shutdown.

Ten seconds should be more than enough time as any blocking network operations (say you were blocked on a SyncConnection read), will be terminated when GNE shuts down all of the sockets -- but if a user thread is in an infinite loop then the thread can never be cleanly stopped unless it returns from its GNE::Thread::run routine.

This means that like typical C++ threading schemes, you must not exit main until all threads are completed. If GNE was the most recent library registered in atexit, then the threads will be shutdown, otherwise some atexit routines may be run. When in doubt, an explicit call to GNE::shutdownGNE will ensure your knowledge of when shutdown occurs.

You may be tempted to use the GNE::Thread::waitForAllThreads method but note that at the current time it polls the thread count every quarter of a second or so and thus is in a sleeping poll loop. I may consider a threading model to allow GNE's shutdown to wait indefinitely by joining on all threads but in C-style threading there are issues with this so I decided to stick to tradition. Feel free to send the GNE authors comments on that decision though.

Table Of Contents

Smart Pointers

In GNE 0.70 I introduced smart pointers into the library, and used them for all main GNE objects. I realized that keeping track of when objects can be deleted in a multithreaded environment was more difficult that necessary, so I decided to utilize reference counted smart pointers. In the 0.70 API change document, I described the smart pointers:

In this new version of GNE I decided to make a move to using smart pointers. The current implementation that I have chosen is Boost's shared_ptr, which is a non-intrusive reference counted smart pointer. In the GNE API, the smart pointers manifest themselves as the GNE::SmartPtr class. Yes, I did find out later the popular Loki library also has a class "SmartPtr" but this is what namespaces are for.

Because SmartPtr is a reference counted pointer, that means when the last SmartPtr pointing to an object dissapears, the object is automatically deleted. Reference counting in this sense appears exactly like garbage collection except for one major flaw -- if an object directly or indirectly (through other classes) points to itself (this is called a cycle), then the object will never be deleted, causing a memory leak. The way to break cycles with boost::shared_ptr is to use boost::weak_ptr, which in GNE manifests itself as GNE::WeakPtr. Weak pointers "become empty" when no strong pointers point to that object -- in other words weak pointers to not keep the object from being destroyed.

Unfortunately this makes the generator-listener relationship difficult. To keep the same design as GNE 0.55 of registering listeners and then being able to "forget" about them, I resolve cycles by keeping a SmartPtr to the listener and manually resetting it when the generator generates its last event. Because Connection and Timer objects are automatically shut down when GNE is shutdown on program exit, no memory leaks will result. This means you can safely retain SmartPtr to GNE's objects in your listeners. I wanted to make the issue of cycles as transparent as possible to the end-developer so I place all of the burden of handling possible cycles with GNE.

Reference counting has a few key advantages over true garbage collection:

GNE enforces the use of smart pointers to its objects by making the constructors private and providing public static "create" methods that construct a new object and return a SmartPtr to it. By forcing objects to be referenced by a smart pointer from the very start, it prevents any accidental leaks, espically unexpected ones due to exceptions.

Table Of Contents

High Level API

The high level API will sit on top of all of the previously described classes and will be the actual "game engine" part of GNE. After the low level part is "completed" with GNE 0.5, work on the high level API will start.

This API will contain classes to manage unique player IDs and data, manage a list of players, and handle things like text communication amongst the players.

About the high-level API in GNE 0.70: Partial experimental work has begun on the high-level API. This work began about a year ago before I decided to refactor the mid-level API and reexamine it for robustness and stability. Instead of removing it for this release I decided to leave the GNE code in its current state. Work will now resume on the high-level parts of GNE, so this API might change. Therefore any parts of GNE marked as "high-level" in the GNE documentation should be considered experimental quality and are provided only as a preview -- their interfaces may change entirely in the next release. You can treat the rest of GNE as being in "late beta". I've tested it somewhat but it hasn't been used in any major applications yet. In addition to the high-level API already with some implementations, there are header files in the include directory of header files with documentation of parts of the GNE high-level API where implementation has not even started (these files only available in the "zip" archive version at this time). I very much welcome your feedback on any parts of the high-level API before I start major implementation work.

Table Of Contents

List Server API

After the completion of the high level API a way to interact with list servers to search for games will be added. Hopefully the GNE team will be able to find a permanent connection and hardware to sponsor a master list service that anyone using GNE will be able to easily register their game servers on.

The list service was meant to address one of the largest problems with independent multiplayer games -- finding others who have the game to play with. The service will act as services like Battle.NET or Half-Life's game lists do. Initially only a searchable database of current game servers will exist but afterwards chat/IM/login functionality might be added.

Helping with GNE

Development of a good API will require the input of many people to assure its usability, performance, flexibility, and functionality. If you are using GNE, I encourage you to join the discussions about GNE on the gnelib-users list, or simply provide feedback, suggestions, and comments on your experience with GNE to me at the GNE website.

Table Of Contents

More Information / Website

For more information, try the GNE website: http://www.gillius.org/gne/
Or the GNE SourgeForge site: http://www.sf.net/projects/gnelib/

For more information on the major API changes from GNE 0.50 to 0.70, view the API changes document at: http://www.gillius.org/gne/apichanges.htm

There is also a mailing list called gnelib-users on the sourceforge website: http://lists.sourceforge.net/mailman/listinfo/gnelib-users

Table Of Contents


Generated on Tue Sep 5 23:47:43 2006 for GNE by  doxygen 1.4.7