diff options
Diffstat (limited to 'libtdegames/kgame/DESIGN')
-rw-r--r-- | libtdegames/kgame/DESIGN | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/libtdegames/kgame/DESIGN b/libtdegames/kgame/DESIGN new file mode 100644 index 00000000..cd737e3a --- /dev/null +++ b/libtdegames/kgame/DESIGN @@ -0,0 +1,407 @@ +This document tries to describe the design of KGame - the KDE multiplayer +library. +This document has been written by: + Andreas Beckermann <[email protected]> + M. Heni <[email protected]> + Burkhard Lehner <[email protected]> + +This document is published under the terms of the GNU FDL + +!!! +Note that this is the initial version of this document and has not yet been +aproved by all core developers (and is far from being complete) +AB: please remove this comments as soon as all KGame hackers have read the +document +!!! + +Please refer the API documentation of every KGame class if you want up tp date +information. + + +0. Contents +----------- + +1. DEFINITIONS +1.1 Message Server +1.2 Client or Message Client +1.3 Master +1.4 Admin +1.5 Server +1.6 Player + +2. Game Negotiation (M.Heni 20.05.2001) + +AB: 3.x is obsolete! +3. Game Properties (Andreas Beckermann 28.07.2001) ( not yet completed ) +3.1 Using KGameProperty +3.2 Custom Classes +3.3 Concepts + +4. KGameIO (Andreas Beckermann 10.08.2001) + +5. Debugging (Andreas Beckermann 06.10.2001) TODO! +5.1 KGameDebugDialog +5.1.1 Debug KGame +5.1.3 Debug Messages + +--------------------------------------------------------------------- +1. DEFINITIONS +-------------- + +First we have to clear some words. The main expressions used in KGame which +need a definition are + +1.1 Message Server +1.2 Client or Message Client +1.3 Master +1.4 Admin +1.5 Server +1.6 Player + +The most important and confusing ones are Master, Admin and Server. We make +quite big differerences between those inside KGame. + +1.1 Message Server: +------------------- +A game has always exactly one object of this class, for local games as well as +for network games. For network games, this object can be on one of the users +processes (usually inside KGame), or it can also be on an independant computer, +that has no idea about what game is played on it. + +A KMessageClient object can connect to it. It's main purpose is transmitting +messages between KMessageClient objects. + +The Message Server is the main communication object. It is represented by the +class KMessageServer. Note that there is also a "Master" and a "Server" which +both differ heavily from the Message Server! + +1.2 Client, Message Client: +--------------------------- +Each process that wants to take part in the game must have a +KMessageClient object, that is connected to the Message Server. KGame creates +this object and connects it to the Messager Server, so that you usually don't +need to create these of your own. Even in a local game (no network) there +must be a message server and one message client connected to it. This is usually +done by the KGame object itself. + +Each message client has a unique ID number (a positive integer value, not zero). +The KMessageClient object, which does the communication with the Message Server +is called "Message Client" and to simplify the use we call any KGame object (or +even the game process) that is connected to a game (i.e. even the Master) just +"Client". + +The main purpose of a Client is to connect to a Master (i.e. to a game) and to +communicate with it. A client has always a KGame object. + +1.3 Master: +----------- +The process that contains the Message Server is called "Master". In any local +game this is the game process. The Message Server is started by KGame using +KGame::setMaster(true) which is automatically done on startup. The Message +Server is deleted automatically as soon as you connect to another Master. +So in most cases there is exactly one KGame object / Client which is Master. But +in one case there can be no KGame object / Client that is Master - if the +Message Server is started as an own process. This "Message-Server-only" process +is called "Master" then, although there is no KGame object which is Master. See +also the definition of Admin! + +1.4 Admin: +---------- +One (and only one) of the Clients is the Admin. He can configure the Message +Server and the game in general in several ways. He can limit the maximum number +of connected message clients and can drop the connection to some other clients, +as well as he can configure game specific ssettings (like max/min players, start +money, ...). The Admin also initializes newly connected Clients. If the Admin +himself disconnects, another Client becomes Admin (The Admin can himself elect +some other Client to become Admin. He himself loses that Admin status then). +An Admin is *alway* a KGame object. The Admin is usually the same as the Master, +but if the Master is an own process (i.e. the Message Server has been started +outside KGame) then Master and Admin differ. An Admin *must* be a KGame object +while the Master doesn't have to be. + +1.5 Server: +----------- +The definition of Server differs quite much from the definition of Master. +A Master just accepts connections and forwards messages. The Server on the other +side checks these messages, calculates results and sends the results to the +Clients. That means the Server does all game calculations and doesn't directly +forward the messages from one Clients to all other Clients. +KGamer makes it possible to write multiplayer games even without a Server. All +Clients just send their moves to the Master which forwards them to all Clients. +Now all Clients calculate the result. +E.g. in a poker game a player selects two of five cards to be exchanges and +clicks on "draw" then the client sends the message "Exchange Card-1 and Card-2" +to the Master. A no-Server solution forwards this to all Clients, and these +Clients exchange the cards of the player. Note that in a no-Server solution +(you can also see it as a "every-Client-is-a-Server solution") all Clients must +have the same random seed and must be of the same version, i.e. the result must +be the same on all Clients. +In a Server-Solution on the other hand the Master forwards the Message +("Exchange Card-1 and Card-2") to the Server only. This Server now calculates +the result, and sends the new cards back to the Client. +Both concepts have advantages and disadvantages. It is on you - the game +developer - to decide which way is better for you. +E.g. the Server-Solution makes it easier for you to write games. The version +must not necessarily be the same, you have one central computer which does the +calcultations. The No-Server-Solution on the other hand decreases network +traffik as the Clients just send their moves and all Clients can calculate the +reactions. I'm sure there are a lot of advantages/disadvantages more for both +concepts. + +1.6 Player: +----------- +A KPlayer object is always connected to a KGame object and represents a +player that participates the game. In a network game, every KPlayer object is +duplicated on every other KGame object connected to the message server with +virtual KPlayer objects. So at every time in the game, every KGame object has +the same number of KPlayer objects. + + +2. Game negotiation +------------------- +Upon connection of a client the admin and the client try to negotiate +the game setup. Basically this means the game of the admin is transferred +(saved) on the client. However, the client's players are added to the game +as far as possible. If the addition of the client's players would add more +players than allowed some players are inactivated. Which players are +inactivated depends on their networkPriority(). This procedure allows +easy replacement of players in a constant number game (e.g. chess). If +this feature is of no interest simply keep the priorities equal (all 0) +and the client will only add only players if the number of players is +less or equal the maximum player number. + +The following is the negotiation procedure as started by the connection +of a client. It is initiated in the negotiateNetworkGame() virtual function +of KGame: + +admin: client: +------------ ------------ +IdSetupGame + QINT16 Library + Version + QINT32 Application + cookie + IdSetupGameContinue; + QValueList<int> player id's + QValueList<int> network priority's + +IdGameLoad + all game data + +IdGameReactivate + QValueList<int> id's + +IdSyncRandom + int randomseed + + +3. Game Properties +------------------ +A very hard task in a network game is consistency. You have to achieve that all +properties of the game and of all players have the same value on all clients +every time. This is because +a) the user might be confused if he sees "Player has $0" on client A but +"Player has $10" on client B and +b) Often game handling depends on those values, e.g. if the example above +happens the computer might quit the game for the Player on client A because +he/she doesn't have enough money. But the game continues on client B. +Another not that easy task is the network protocol itself. You have to write +several send() and receive() functions which apply changed values of properties +to the local property. + +KGameProperty is designed to do all of this for you. KGameProperty is +implemented as a template so you can use it theoretically for every type of data +- even for your self defined classes. + + +3.1 Using KGameProperty +----------------------- +It is basically very easy to use a KGameProperty. You first create your own +class containing the property, e.g: +class MyGame : public KGame +{ +[...] +protected: + KGamePropertyInt money; + KGamePropertyQString name; + KGameProperty<AntotherClass> myProperty; +}; +KGamePropertyInt is just a typedef for KGameProperty<int> - just like +KGamePropertyQString. Now you need to register the properties in the constructor +of the class to the KGamePropertyHandler: +MyGame::MyGame() : KGame(myCookie) +{ + money.registerData(KGamePropertyBase::IdUser+1, dataHandler(), "Money"); + name.registerData(KGamePropertyBase::IdUser+2, this, "Name"); + myProperty.registerData(KGamePropertyBase::IdUser+3, dataHandler(), "MyProperty"); +} +-> You need to specify a *unique* ID. This ID must be greater than +KGamePropertyBase::IdUser. IDs below this are reserved for KGame. Probably this +will be changed so that you cannot use IDs below IdUser in the future. Then you +have to specify the dataHandler(). You can also use a KGame or KPlayer pointer. +This will automatically use KGame::dataHandler() or KPlayer::dataHandler(). +Finally you *can* provide a name for the property. This will be used for +debugging in KGameDebugDialog. If you want to save some memory you can leave +this out. +Note that if you use pointers to create the properties dynamically they are +*not* deleted automatically! You MUST delete them yourself! +Now you can use the KGameProperty like every variable else. See also Section +"3.3 Concepts" for restrictions in use. + +3.2 Custom Classes +------------------ +To make custom classes possible you have to implement several operators for your +them: you need at least << and >> for QDataStream as well as "==" for your own +class. To overload the "<<" you would e.g. do something like this: +QDataStream& operator<<(QDataStream& stream, MyData& data) +{ + int type = data.type; + QString name = data.name; + stream << type << name; + return stream; +} +So you basically just have to split your class to several basic types and stream +them. + +3.3 Concepts +------------ +You can use KGameProperty basically in two completely different ways. You can +also use a mixture of both but this is not recommended. The default behaviour +and therefore also the recommended is the "clean" way: +a) Always Consistent. This means that a KGameProperty has always the same value +on *every* client. This is achieved by using KGameProperty::send() whenever you +want to change the value using "=". You can still use changeValue() or +setLocal() but send() will be the default. If you use send() then the value of +the property does *NOT* change immediately. It is just sent to the +KMessageServer which forwards the value to all clients. As soon as the new value +is received from the message server the KGamePropertyHandler (a collection class +for KGameProperty) calls KGameProperty::load() and changes the value of the +property. So the game first has to go into the event loop, where the message is +received. This means to you that you cannot do this: +myIntProperty = 10; +int value = myIntProperty; +As myIntPoperty still has the old value when "value = myIntProperty" is called. +This might seem to be quite complex, but +KGamePropertyHandler::signalPropertyChanged() is emitted whenever a new value is +assigned so you can connect to this and work immediately with the new value. +You gain the certainty that the value is the same on every client every time. +That will safe you a lot of time debugging! +Another way is the "dirty" way: +b) Not Always Consistent. Sometimes you really *want* to do something like +myIntProperty = 10; +int value = myIntProperty; +but this is not possible with the default behaviour. If you call +KGameProperty::setAlwaysConsistent(false) in the constructor (right after +registerData()) you get another behaviour. "=" means changeValue() now. +changeValue() also uses send() to change the value but additionally calls +setLocal() to create a local copy of the property. This copy now has the value +you supplied with "=" and is deleted again as soon as any value from the network +is received. + +4. KGameIO +---------- +The class KGameIO is used to let the players communicate with the server. You +can plug as many KGameIO objects into a player as you want, e.g. you can plug a +KGameMouseIO and a KGameKeyIO into a player so that you can control the player +with the mouse and the keyboard - e.g. in a breakout game. +You can probably see the advantage: as most of the control stuff is common in a +lot of games you can use the same IO class in many different games with very +small adjustments. +You could also put all the IO stuff directly into your KPlayer object, like +sendBet(int money) for a poker game. But there is a major disadvantage and I'm +very sure you don't want to use a KPlayer object for your IO stuff as soon as +you know which disadvantage: +KGameIO is designed to be able to switch between different IOs "on the fly". So +you might have a KGamePlayerIO, derived from KGameIO, for your game. But now +this player (who "owns"/uses the KGamePlayerIO) leaves the game (e.g. because he +was a remote player). So now the game would be over for every player as one +player is now out of order. But with KGameIO you can just let any of the +remaining clients create a KGameComputerIO and plug this into the player. So the +player now is controlled by the computer and the game can continue. + +Think about it! You don't have to care about removing players when a player +leaves as you can just replace it! The same works the other way round: imagine a +game with 10 player (e.g. 5 human and 5 computer players) that has already +started. You cannot add any further players without restarting. So if there are +any additional player you can just call KPlayer::removeGameIO() which removes +the IO of a computer player and then call KPlayer::addGameIO() for the same +player which adds a GameIO for new human player. That's all! + +To achieve this you just have to make sure that you make *all* of your IO +operations through a KGameIO! So instead of using MyPlayer::sendBet(int money) +you should use something like MyIO::sendBet(). The amount of money would +probably be calculated by the game IO itself. + + + +5. Debugging +------------ +The general debugging concept (if there is one at all) or general debugging +hints are not yet written. Feel free to do so + +5.1 KGameDebugDialog +-------------------- +A nice way of debugging a KGame based game is the KGameDebugDialog. Basically +all you have to do is to add something like "Debug" to your game's menu and add +a slot like +slotDebug() +{ + KGameDebugDialog* dialog = new KGameDebugDialog(mGame, this); + connect(dialog, SIGNAL(finished()), dialog, SLOT(slotDelayedDestruct())); + dialog->show(); +} +that's it. +You can now click on that menu entry and you get a non-modal dialog where you +can start to debug :-) +The dialog consist of several pages. You can easily add your own using +KDialogBase::addVBoxPage() (for example). + +5.1.1 Debug KGame +----------------- +The first page, "Debug KGame" shows on the left most or even all status values of +KGame. That contains e.g. minPlayers(), isAdmin(), gametqStatus(), ... +The right side is probably the more important one. It lists *all* KGameProperties +which have been inserted to this KGame object (only to this KGame object - not +the ones that have been added to the players!). Most of the status variables of +the left side are here again as they are implemented as KGameProperty. You can +see the name of the property (together with its ID), its value and the policy +this property uses. Note that "unknwon" will be displayed as name of the +property if you haven't supplied one. See KGamePropertyBase::registerData() for +info. You probably always want to supply a name for the property to debug it +easily. In the future there will be something like +KGamePropertyHandler::setDebug() so that you can switch off debugging and save +the memory of the names in a release version. +For as long as you use standard types for your properties (int, long, bool, +...) you should always be able to see the value of the property. If you just see +"unknown" then this type has not been implemented. You can connect to the signal +KGamePropertyHandler::signalRequestValue() and supply a QString with the value +yourself. If you do so for a standard type please also submit a bug report! + +Currently the dialog does *not* update automatically! So you alway have to click +the "update" button when you want a current value. There are several reasons for +this (and one of them is that i'm too lazy to implement the update ;)). E.g. +often (very often) a property is just in the background - stores e.g. the +available money in a game. But you don't want it to update whenever the value +changes (a player receives/pays money) but only when the value on the screen +changes. + +5.1.2 Debug Players +------------------- +This page consists of three widgets. On the very left there is a list of all +players in the game. Only the IDs are displayed to save space. If you click one +the other widgets are filled with content. These widgets are quite much the same +as the ones in "Debug KGame" - the left shows the value of the functions and the +right one displays all KProperties of a player. Not much to say here - except: +See "Debug KGame". + +If you change to another player the value are also updated. + +5.1.3 Debug Messages +-------------------- +This page is probably not as important as the other ones. It displays *every* +message that is sent through the KGame object. As a KGameProperry also send +messages you probably get a lot of them... +You can exclude message IDs from being displayed (e.g. all game properties). +You can also change the sorting of the list to see all messages of a certain ID. +The default is to sort by time (which is displayed on the left side). + |