Code documentation

From FreeAllegiance Wiki
Jump to: navigation, search

Overview

The key components of Allegiance are:

  • The client - Allegiance.exe
  • the server - AllSrv.exe and the UI tool AllSrvUI.exe
  • the lobby - AllLobby.exe

In a typical configuration there are many game servers and clients (players) which connect to a single lobbyserver. The lobby is the central communication place where servers announce themselves (and the games they're hosting) and where clients can find, join or create games on a chosen server. A server can host many games at once but a client can join only one server and one game at a time.

These keys components share many lines of code with the use of common libraries. The most notable ones are the messaging API library which is built on Microsoft DirectPlay and the IGC library which handles the game logic.

(The picture below is difficult to understand, especially why it is there, and what the layout means. Perhaps an explanation about it should be added here? - juckto)

Allegiance Architecture Overview
Allegiance Architecture Overview
Click on the image to view a larger version. Popup.png
Edit.png
Stub This article is incomplete

This is an article about a topic that should be covered in more detail by the FreeAllegiance Wiki, but is lacking in content.

You can help by improving it!


ZLib and Utility libraries

The ZLib library is a set of helper classes. It's used by all projects in the allegiance source.

The most notable items of ZLib are:

  • the ZString class which deal with strings.
  • the TRef<T> template class which deal with object pointers and automatic garbage collection.
  • some maths objects (vector, matrix,...)
  • the Window class and win32 main entry point

The Utility library deals with more complex stuff than the ZLib library:

  • the collision API which use Convex Hull
  • the messaging API (network code) which is build on top of DirectPlay
  • dynamic linked lists of pointers used widely in the several parts of the source.


IGC library

IGC stands for Internet Game Core. It's the game logic library (API) and it's shared between clients and servers.


IGC Interfaces & Objects

IGC is accessed with of a set of hierarchical abstract classes (interfaces) that hold all the game objects (ships, stations, sectors, etc) and their current properties (position, speed, etc). The top interface is ImissionIGC which represents a game. ImissionIGC is implemented in the CmissionIGC class (src\Igc\missionigc.cpp). It holds lists of all other objets (ships, stations, etc) and provides methods for accessing them. These lists are all implemented with template classes (Slist_utl<> and Slink_utl<> which can be found in the Utility library).

Class Diagram
Class Diagram
Click on the image to view a larger version. Popup.png

The most notable method of ImissionIGC is the the 'Update' member method. It is called every ticks on the server and it's propagated in the various IGC object lists and update their states according to the game logic.

When the game needs to create a new object the IGC library usually provides a 'template' for this object, instead of the game creating it from scratch. The template holds several attributes that are used as initial values for the corresponding attributes of the new object. There can be many different templates for a given object type and the game must tell (tell who? -juck) which template to use when creating an object. This is how there can be different factions with different stations, ships and weapons.

For example: the class representing active missiles is CmissileIGC, it uses the ImissileIGC interface and a new missile is initialized from a chosen CmissileTypeIGC (ImissileTypeIGC interface). Check the IGC classes diagram for the list of all IGC interfaces including the template ones.

All these templates are stored in static lists of IGC objects and because they are constant they're not transmitted between the server and the clients. Instead the data is stored into what we call a core file. So when a client joins a game on a server the server tells the client the core file name the game is using and the client will load it from its local artwork folder. This process avoids having to send large files over the network. If the file doesn't match then the client will get an error message "files out of sync".

IGC Callbacks

Since both server and client share the IGC code many of the game state changes can be handled on the client side alone, without the need for sending information over the internet.

For example: when a ship is destroyed the client will need to draw the ship explosion but the server does not. However the server does need to propagate that event to the other clients (or at least to the clients which need to know about that explosion).

Both client and server are said to be 'consumers' of the IGC library.

Consumers of the IGC library must implement the IsiteIGC interface in order to be called upon game state changes. The server implements it in the FedSrvSiteBase class and the client in the BaseClient class. We can view the IsiteIGC interface as a set of event callback functions. Understanding how this works is the main step of understanding the whole IGC library. IsiteIGC is not the only callback set, there are others:

  • the ThingSite interface which deals with objects having a model (mainly all IGC objects derived from TmodelIGC<T>)
  • the ClusterSite intertace which deals with sectors.

These allows to add callbacks on a per object scope instead of using only the global ones of IsiteIGC.


Client/Server communication & updates

Since both client and server share the same IGC code but react differently to it, only a subset of the game logic updates are done within the IGC library. The main entry for this is CmissionIGC::Update(...) which is called every tick on all clients and server (but each client has only a subset of the a game IGC objects whereas the server has everything).

The remaining game logic updates are all handled by the server. This includes collisions, damages, object creations and some object deletions (some object deletions are processed inside IGC library and so are performed on all sides during the Update(...) without requiring network exchanges).

Even if IGC is the game logic layer, a lot of game logic code isnt in it. So keep in mind when you are making changes to the game logic: they require careful inspection and knowledge in order to be performed correctly - it's not all in the IGC library.


WinTrek - Allegiance Client

Allegiance.exe is the game client. It is build from many subprojects, the top one being src\WinTrek.

  • The client (refered as WinTrek hereafter) consists of several layers on top or next of each other.
  • The lower one is ClintLib which is the minimalist game client without any UI at all. It deals with everything needed to connect to lobby/servers and handles the game logic.
  • WinTrek is the code that links ClintLib with 3 engines (gfx, effects and sound) and a training module in order to produce Allegiance.exe.

These various components are explained below.


ClintLib

The ClintLib name is presumed to be a shortcut for "Client Library". It's a library project that use IGC library and produces an interface-less, minimalist game client that can fully communicate with game servers and the lobby. The main class of ClintLib is BaseClient from which any working allegiance game client needs to inherit from. As of today, only 2 known executables are built on it: Allegiance.exe and the Pigs test system. ClintLib is totally independent of the "engines" layers. Its purpose is to isolate everything that is about game logic and network communication. It's definitely the starting foundation on which one could write a brand new client with a new gfx engine for instance.

Graphic engine

This is the graphical engine. It deals with .. TBC

Edit.png
Stub This article is incomplete

This is an article about a topic that should be covered in more detail by the FreeAllegiance Wiki, but is lacking in content.

You can help by improving it!


Effect engine

The effect engine is built on top of the graphic engine... TBC

Edit.png
Stub This article is incomplete

This is an article about a topic that should be covered in more detail by the FreeAllegiance Wiki, but is lacking in content.

You can help by improving it!


Guide to sounds:

MDL side: Sounddef.mdl contains two things: mdl sound objects defined with mdl calls to the actual sound files, and a table relating all these sound objects to the name the game engine will call them by. Core-defined sounds call by numbers 1-1000, non-core sounds call by name.

Eg:

MDL sound object:

faohmu2ShotSound           = GainSound(SFXGain, PrioritySound(-1.5, ThreeDSound(150, ImportWave("faohmu2"))));

Then at the bottom of sounddef.mdl we have:

(655, faohmu2ShotSound),

This references that sound to Core sound ID 655.

We also have general non-core sounds, called by name. Example:

newShipSound                = GainSound(SFXGain, ImportWave("newtarget"));

(newShipSoundId, newShipSound),


For non-core sounds, we must update sounds.h, as it contains a list of references to all non-core sounds.

DEFSOUND(newShip)

Core sound references are contained within their type objects. Eg:

IafterburnerIGC* pafterburner = 
           (IafterburnerIGC*)(m_pship->GetMountedPart(ET_Afterburner, 0));

pafterburner->GetInteriorSound();
pafterburner->GetExteriorSound();

Or:

const IhullTypeIGC* pht = m_pship->GetHullType();
pht->GetMainThrusterInteriorSound();
pht->GetManuveringThrusterInteriorSound();

The core file loader will load the sound references into their appropriate objects in memory, most of which have some sort of GetInteriorSound() and GetExteriorSound() calls.

Non-core sound references are called by the name defined in Sounddef.mdl + a Sound suffix.

Example for hullLowSound:

if (bIsPlayersShip && fNewHullFraction < 0.15f && m_fHullFraction >= 0.15f)
               trekClient.StartSound(hullLowSound, GetSoundSource());


Sound sites:

In trekigc.cpp:

Sound objects are implemented through the SoundSite interface in trekigc.cpp Two subclasses that matter: AmbientSoundSite, ShipSoundSite

ShipSoundSite controls sounds coming from the player ship.

void PlaySoundIf(TRef<ISoundInstance>& pSound, SoundID id, 
           ISoundPositionSource* psource, bool bPlay)

ISoundInstance is the sound instance. This must be defined private within the SoundSite.

Eg:

Private:
      TRef<ISoundInstance> m_pPilotInteriorSound;


SoundSite has function GetSoundSource() which returns the location object for the sound to be broadcasted from or heard at.

Sound Template Objects and sounddef.mdl When loading the game, WinTrek.cpp calls: SoundInit::InitializeSoundTemplates(GetModeler(), m_vSoundMap); See soundinit.cpp

This reads the sound ID definitions at the end of sounddef.mdl. For each sound definition, the mdl parser creates the appropriate sound template objects with behaviour chosen by the mdl calls. Pointers to these objects are stored in m_vSoundMap within WinTrek.cpp

Sound templates are defined in soundtemplates.h and soundtemplates.cpp

These are sibling classes with varying sound behaviour – such as loops, play once, varying priority, pitch/gain variation, etc…

Controlling sound objects:

void PlaySoundIf(TRef<ISoundInstance>& pSound, SoundID id, 
           ISoundPositionSource* psource, bool bPlay)

SoundID is the call to sound ID itself. This is the Core sound ID number, or the name defined through sounds.h (eg: 655, or newShipSound). Bool is true to start a sound, false to stop a sound.

psource must be a call to GetSoundSource() of the SoundSite object you want the sound to broadcast from.

PlaySoundIf calls start/stop sound as such:

pSound = trekClient.StartSound(id, psource);
pSound->Stop();
pSound= NULL;


Then:

 TRef<ISoundInstance>  StartSound(SoundID soundId, ISoundPositionSource* psource = NULL)
   {
       if (soundId < 0 || soundId > m_vSoundMap.GetCount())
       {
           // may avoid some art crashes in retail builds
           ZAssert(false);
           return NULL;
       }

       return StartSound(m_vSoundMap[soundId], psource);
   };

This looks up the sound in the table and gets the associated SoundTemplate.


TRef<ISoundInstance>  StartSound(ISoundTemplate* ptemplate, ISoundPositionSource* psource = NULL)
   {
       if (ptemplate)
       {
           TRef<ISoundInstance> pSoundInstance;
           if (ZSucceeded(ptemplate->CreateSound(pSoundInstance, m_pSoundEngine->GetBufferSource(), psource)))
           {
               return pSoundInstance;
           }
       }
       {
           // may avoid some art crashes in retail builds
           return NULL;
       }
   };


This creates a new ISoundInstance and calls down to the appropriate playing behaviour from the sound templates.

pSound()->Stop(); calls the stop behaviour defined in the sound template.

Training

Edit.png
Stub This article is incomplete

This is an article about a topic that should be covered in more detail by the FreeAllegiance Wiki, but is lacking in content.

You can help by improving it!


FedSrv - Allegiance Game Server

AGC Library

AllSrvUI

Edit.png
Stub This article is incomplete

This is an article about a topic that should be covered in more detail by the FreeAllegiance Wiki, but is lacking in content.

You can help by improving it!


Lobby - Allegiance Lobby Server

Edit.png
Stub This article is incomplete

This is an article about a topic that should be covered in more detail by the FreeAllegiance Wiki, but is lacking in content.

You can help by improving it!


Tools

XMunge

XMunge is a build time tool aimed at manipulating DirectX .X files. XMunge uses Direct3D Retained Mode which has been abandoned due to low adoption. This tool definitely could use a complete rewrite.

Pigs

Pigs are a set of testing tools. Their main purpose is to provide a way to simulate many allegiance clients by using automated 'bots' that behave according to various scripts. This allows a single developer to simulate a game with many players during testing.

To do so, the Pigs use the same Clintlib library than the game client in order to fully behave like real clients (at least as seen from the server). This is handy to stress test the server, IGC, and networking APIs.

mdlc

MDLC is a build time tool aimed at performing some manipulations on MDL model files. For instructions on how to use it see mdlc.

One important thing about MDLC is that its code use the same engine code (src\engine) than the allegiance client, so it is always in sync regarding what models the client can handle.