[Kde-games-devel] Tutorials for GGZ-in-kdegames

Josef Spillner spillner at kde.org
Mon Feb 26 09:37:20 CET 2007


Hi,

I felt like writing some tutorials on the matter now that the sources have 
been imported into SVN.

The next goal for me is to implement the gameplay in KReversi. This will in 
turn need some decisions about how to let the UI reflect the multiplayer 
status. For example, will we simply grey out the multiplayer dialogs when the 
game is run in singleplayer mode, or will we hide them completely? Likewise, 
certain actions like "new game" will behave differently in a multiplayer 
setting.

Josef
-------------- next part --------------
GGZ Gaming Zone for KDE 4 - Tutorial 0
--------------------------------------

There will be 3 tutorials for GGZ in KDE, one for each library (kggzmod,
kggznet, kggzgames). We will start with kggzmod since this is probably
the most interesting one. However, before starting, this tutorial 0
should give some information about the build system and general
GGZ game module information.

At some point the tutorials, currently sent by e-mail, will be converted
to HTML and put onto developernew.kde.org or games.kde.org, depending
on where game development documentation should go to.

Note that in addition to the tutorials, the GGZ libraries all ship with
full API docs now, which can be consulted online at:
	http://www.ggzgamingzone.org/docs/api/kggzmod/
	http://www.ggzgamingzone.org/docs/api/kggznet/
	http://www.ggzgamingzone.org/docs/api/kggzgames/
Simply running 'doxygen' for each library will also work of course.
The API docs will end up somewhere at api.kde.org in the standard KDE
apidox format eventually.

Build system
------------

All build issues are handled by GGZ.cmake, which at the time of writing lives
under kdegames/cmake/modules. For some reason, calling
  include (../cmake/modules/GGZ.cmake)
or similar seems to be necessary for each CMakeLists.txt which wants to make
use of it. This will be improved in the future.

GGZ.cmake sets up some variables and helps with GGZ module registration.
Modules are game clients which can run on GGZ and which are registered in a
central system-wide file so every GGZ core client can find them.

All that is needed for KDE games making use of GGZ is to link against the
kggz* libraries in kdegames and to install a module.dsc file containing the
registration data. In terms of CMake, this looks like this:

  register_ggz_module(module.dsc)
  target_link_libraries(mygame ... ${KGGZGAMES_LIBS})

The include directories must include libkdegames, but usually this is already
the case. If not (e.g. for games not in KDE SVN), the following helps:

  include_directories(${KGGZGAMES_INCLUDE_DIR})

GGZ modules
-----------

At the moment, this tutorial assumes that game clients are written for game
servers which already exist, or that the developer knows how to write GGZ game
servers.
Either way, the client and server are identified on the basis of a protocol
engine and an associated version number, both of which must match exactly.
A module.dsc file contains this information and some more:

[ModuleInfo]
Name = ...
Author = ...
CommandLine = <executable-name>
Frontend = kde
Homepage = http://games.kde.org/...
ProtocolEngine = Reversi
ProtocolVersion = 4
Version = ...

In the example above, Reversi:4 is determined by the server, and the client
confirms this combination by stating that it will understand the Reversi
protocol as of version 4. Should the protocol change on the server, the user
will be notified accordingly.

GGZ game servers
----------------

Help out getting network code into as many games as possible! Several KDE
games look like they could match GGZ game servers, so development will be
easy.
Have a look at http://www.ggzgamingzone.org/gameservers/ for a full list
of GGZ and external game servers.
If you write a game server, make sure to have it added there (assuming it
runs on GGZ).

-------------- next part --------------
GGZ Gaming Zone for KDE 4 - Tutorial 3
--------------------------------------

This is the third tutorial for GGZ in KDE, this dealing with kggzgames.
The tutorial is a really dull one, since kggzgames offers so little
currently that one line of code seems sufficient :)

The kggzgames library is supposed to contain the graphical widgets and
dialogs needed for good multiplayer support in game clients. Currently,
it only contains the KGGZSeatsDialog class.

KGGZSeatsDialog
---------------

This dialog is a very autonomous one. Given an active GGZ connection,
calling its constructor is already enough to let it perform all work
on its own.
It will list all the participating players/bots/spectators for a game,
but also unused seats (empty/reserved/abandoned).
If the privileges of the player are sufficient, then the seat configuration
can be changed, e.g. by kicking some players or bots or by filling up
empty seats with new bots.
Highscores/ratings/rankings are also shown in this dialog.

In the future, several more classes could be added here.
For example, libkdegames already provides a chat widget and a chat dialog.
Using kggzgames, it could be possible to use the chat dialog on an
existing GGZ connection, preconfiguring it to know all present players
and automatically sending to and receiving from the game server (if it's
game chat) or the GGZ server (if it's table or room chat).

Likewise, a global highscore dialog and a connection dialog could go
in here.

-------------- next part --------------
GGZ Gaming Zone for KDE 4 - Tutorial 1
--------------------------------------

This is the first of the three tutorials about the kggz* libraries
in libkdegames, and it covers the kggzmod library.

What kggzmod is used for is to connect your game to the gaming zone, to
let it receive information about the players and spectators and scores,
and to let it submit requests to change the seat configuration or similarly.
It doesn't do anything else, in particular it doesn't let your game client
communicate with your game server. There are other libraries for this task,
some of them being part of kggznet.
The kggzmod library also doesn't offer graphical interfaces to display
the information or let the user modify anything - this would be the task of
the kggzgames library.
Therefore, kggzmod is a non-graphical base component for GGZ integration
of game clients.

KGGZMod::Module
---------------

Strictly spoken, this is the only class in kggzmod which must be known by
the game author. There are other classes, but some are used by kggzgames
on its own and some are only necessary for advanced features, so implementing
everything which KGGZMod::Module has to offer is already all of the work
for good GGZ integration.

A module object should only be created if the game runs in GGZ mode. The
static method ::isGGZ() can be used to check for this condition.
A module will offer two signals, one for data from the game server and one
for errors which might happen anywhere. Therefore, a good initialisation
code looks like:

void initMultiplayer()
{
  if(KGGZMod::Module::isGGZ())
  {
    KGGZMod::Module *mod = new KGGZMod::Module("mygame");
    connect(mod, SIGNAL(signalError()), SLOT(slotError()));
    connect(mod, SIGNAL(signalNetwork(int)), SLOT(slotNetwork(int)));
  }
}

Advanced usage is possible by also connecting the signalEvent() signal,
which will deliver a KGGZMod::Event object which might be casted to more
specialised KGGZMod::FooEvent objects. The module object also allows to
print out information about the player via ::self() or about other players
via ::players(), the first one being a KGGZMod::Player* object and the
second one being a list of them which contains oneself.

In order to finish GGZ mode, simply delete the KGGZMod::Module::instance()
object.

One word about the parameter to the constructor: Right now, this is a
meaningless string somehow related to the name of the game. In the future, we
want this to refer to the *.dsc file (see tutorial 0) so we can make the game
self-aware of its own version number and features. The API for this hasn't
been decided on yet.

-------------- next part --------------
GGZ Gaming Zone for KDE 4 - Tutorial 2
--------------------------------------

This is the second tutorial for GGZ in KDE, now dealing with kggznet,
after kggzmod was handled already. Actually kggzmod uses kggznet internally
but this is not relevant for us to know. We will only look at how kggznet
can be used in games.

The task of kggznet is an easy one: networking. It provides some C++ classes
for handling the communication between a game server and a game client.
It is important to know that the kggznet libraries do not have to be used
with every game. However, they should be used whenever compatibility with
existing game servers (or clients) is needed which already use the same
protocols. Those protocols are 'easysock' and 'dio' from the GGZ Gaming Zone
project and are in use with several games in GGZ, GNOME games and various
other game projects. Both are binary protocols. This makes them efficient
but terribly hard to debug. Some debugging facilities are included in
kggznet to help out.

In the future, we want to have abstract game protocol descriptions and
generate the actual networking code automatically from it. This is possible
to some extent already in an experimental fashion, but not ready for
production yet, using the GGZComm protocol generator. Therefore, we recommend
to use kggznet right now and switch to generated code later.

KGGZRaw
-------

This is one of the two classes in kggznet. It can be used similary to a
QDataStream. However, QDataStream works best with buffered sockets, whereas
there are certain conditions when unbuffered sockets are wanted - for example,
if after reading a certain value the socket handling should be switched to
another handler, or if partial value reads should be forbidden.
KGGZRaw doesn't offer all Qt type serialisations mostly because the Qt types
serialise themselves to QDataStream instead of letting QDataStream serialise
them, and therefore have QDataStream hardcoded. If you need Qt types in
KGGZRaw, they could be added, but keep in mind that other implementations
of the same class will likely not be able to read them! Therefore, adding
is only possible when the type can easily be deconstructed into two parts,
for example writing a QSize in a KDE game and reading two integers (x, y)
in a game server written in plain C.

Usage example: Add a KGGZRaw* pointer to your class and initialise it to
NULL. When the KGGZMod::Module object reports the file descriptor to the game
server via signalNetwork(), check if the pointer is still NULL, and if so,
create the KGGZRaw object and assign the file descriptor. Just in case, the
error signal should also be slotted in somewhere.

// matches KGGZMod::Module::signalNetwork(fd)
void slotNetwork(int fd)
{
  if(!m_raw)
  {
    m_raw = new KGGZRaw();
    m_raw->setNetwork(fd);
    connect(m_raw, SIGNAL(signalError()), SLOT(slotError()));
  }

  // now read from m_raw
  int opcode;
  m_raw >> opcode;

  // and write back the answer
  int answer = 42;
  m_raw << answer;
}

// called by kggzraw in case of read/write errors
void slotError()
{
  delete m_raw;
  m_raw = NULL;
  // don't forget to inform the user!
  // in GGZ game clients, we likely want to terminate everything now
  delete KGGZMod::Module::instance();
}

KGGZPacket
----------

KGGZRaw has serious drawbacks: due to it being unbuffered, it might block the GUI
if an integer (4 bytes) is read but only 3 bytes are in the buffer at this time,
which might actually happen in practice on TCP/IP connections!
Blocking is not bad if it happens in a dedicated thread only, but usually game
clients are single-threaded and we want non-blocking network operations.

Enter KGGZPacket: Each 'packet' is a collection of integers, characters and
strings which somehow fit together as a logical unit. The format of the packets
is left up to the game authors. Packets are used in Freeciv, for example, but
also in other games.

The interface is similar to KGGZRaw, but is not the same one. The reason behind
the difference is that KGGZPacket might need to read several times before a packet
is finished. Since buffering is not an issue, the developer also gets access to
a standard QDataStream, one for reading and one for writing. The example from
above would read as follows, in case we have a KGGZPacket *m_packet member in
our class and want to read whenever KGGZMod::Module *m_mod reports data from
the game server:

void initNetwork()
{
  m_packet = new KGGZPacket();
  connect(m_mod, SIGNAL(signalNetwork(int)), m_packet, SLOT(slotNetwork(int)));
  connect(m_packet, SIGNAL(signalPacket()), SLOT(slotPacket()));
}

void slotPacket()
{
  // now read from m_packet - which is guaranteed to be successful
  int opcode;
  *m_packet->inputstream() >> opcode;

  // and write back our answer packet
  int answer = 42;
  *m_packet->outputstream() << answer;
  *m_packet->flush(); // don't forget this!
}

So basically, KGGZPacket is used as a redirector for the network traffic which takes
the raw traffic and cuts it into nicely usable packets with a known size but unknown
content.

A higher-level protocol code could also deliver known content, that is, one special
struct or object on the stack for each incoming message. However, this is specific
for each game, and can be implemented by game developers as needed. GGZComm-generated
code will support such higher-level packets.



More information about the kde-games-devel mailing list