Pyrogenesis Engine Overview
Life of a Game Session
The game logic code works the same way whether the game is multiplayer or single player - all that differs is how commands are treated. We'll first describe how the game logic code is organized before explaining the details of setting up multiplayer. The game logic is implemented in the simulation module, most notably in CSimulation, which handles all updates, and CEntity, which represents and updates an in-game object (unit, building, etc). In both multiplayer and single player, the game state is updated in turns, which are about 150 milliseconds each. Each turn, objects move to some new position, units may gather resources or do damage (depending on their gather rates), etc. A turn is handled in the CSimulation::Update method. In addition, between turns, the graphical objects in the game are animated continuously as fast as the frame rate permits by interpolating between their previous turn's position and their next turn's position. This is done by CSimulation::Interpolate. There is a CTurnManager object which says when it is time for a new turn (the simulation queries this object each frame). While the game is running, commands from the player (obtained through the GUI) are queued up using CTurnManager::QueueLocalCommand. Each turn, the turn manager provides a batch of commands to the simulation based on what was queued up. The only difference between single player and multiplayer is which turn manager is used: The multiplayer turn manager sends commands to the host, which buffers a batch of orders and then broadcasts them to all players, thus making sure that all clients get the same batches of commands, keeping their simulations in lockstep. The single player turn manager sends commands directly to the simulation. All commands are validated before being played, to prevent cheating. When AI is implemented, it will be done by simply sending orders from the AI player to the order queue as if a human player had issued them.
In summary, a game runs like this:
- Loop forever
- Check the current time
- If turn manager says it is time for a new turn, call CSimulation::Update
- Else call CSimulation::Interpolate
- Handle inputs (queue up orders)
- Render a new frame
Most of the game logic happens in CEntity and its related scripts (binaries/data/mods/official/entity_functions.js) and helper classes (like CEntityManager). All objects that a player may interact with in the game are entities - including units, buildings, trees, any obstacle that has an effect on pathfinding, etc. Each entity is represented in the game world by an actor - a graphical mesh with potentially some other meshes attached to it at prop points (things like shields, weapons, or the rider on a horse). There are also purely decorative objects that are not entities, such as grass blades or shrubs. These are implemented by having an actor with no entity. Actor drawing and animation is handled in the graphics package, including loading meshes and animations from 0 A.D.'s custom compressed formats, PMD (Pyrogenesis MoDel) and PSA (PyrogenesiS Animation).
The graphics in 0 A.D. are handled by two packages - graphics, which manages graphical objects like meshes, animations and textures, and renderer, which figures out what items to draw and also manages global effects such as shadows and water rendering. Sound is implemented in the sound module and provides basic support for playing music and playing short sounds on various events. The game view (including camera) is maintained in CGameView (graphics/GameView.cpp). Player input is handled in engine/Interact.cpp.
One final thing to note about game life is how the map editor, Atlas, works. Atlas is launched by running pyrogenesis with the -editor option. It creates a window using the wxWidgets library, and then runs a special copy of the game within this window. This makes it possible to render objects in Atlas using the same code that renders them in the game, and to start testing the game at any time by pressing the Play Simulation button in Atlas. The Atlas GUI is also scriptable. It is implemented in binaries/data/tools/atlas/scripts. Atlas also supports hotloading GUI scripts, so it is possible to edit a script and immediately see its effect in a running Atlas window. The goal is to eventually support hotloading for the game GUI and possibly even game logic scripts in 0 A.D.
Atlas (Map Editor)
To build 0. a.d., one can follows the Build Instruction page. In general, Pyrogenesis engine reads setting from binaries/data/config/default.cfg for configuring e.g. fragment shaders, vertex shaders, etc. Configuration can be tweaked by
- create local.cfg (cp default.cfg local.cfg)
And disable/ enable some features such as
- fancywater=false (to avoid fragment shaders)
- renderpath=fixed (to avoid vertex shaders)
Reference: Driver problem
Useful Features for Testing
Outline for this document (from Gobby):