|
This document is under active development and discussion!
If you find errors or omissions in this document, please don’t hesitate to submit an issue or open a pull request with a fix. We also encourage you to ask questions and discuss any aspects of the project in GitHub Discussions. New contributors are always welcome! |
Getting Started
Flexible Isometric Free Engine (FIFE) is a multi-platform isometric game engine written in C. It comes with Python bindings allowing users to create games using Python as well as C. The engine is extendable and enables you to add any feature you can imagine to your project. It’s a very flexible game creation framework and not tied to any genre, but geared towards an RTS or RPG using an isometric or top-down view style.
The developer manual offers programmers documentation and examples useful in working with fifengine.
Prerequisites
To work with FIFE effectively, you should be familiar with:
-
C++17 — the engine core is written in C++
-
Python 3 — for scripting and binding development
-
CMake — used as the build system for all platforms
-
Basic game engine concepts — entity/component patterns, rendering pipelines, event systems
System Requirements
| Resource | Windows | Linux | macOS |
|---|---|---|---|
OS |
Windows 10+ |
Ubuntu 20.04+, Fedora 36+, Arch |
macOS 12+ |
Disk Space |
~2 GB (with dependencies) |
~1.5 GB |
~1.5 GB |
RAM |
4 GB minimum, 8 GB recommended |
4 GB minimum, 8 GB recommended |
4 GB minimum, 8 GB recommended |
Recommended IDE Setup
Visual Studio Code (all platforms)
Install these extensions for FIFE development:
-
C/C++ (ms-vscode.cpptools) — IntelliSense and debugging
-
CMake Tools (ms-vscode.cmake-tools) — CMake integration
-
Python (ms-python.python) — Python support
-
Clangd (llvm-vs-code-extensions.vscode-clangd) — advanced C++ linting
Visual Studio (Windows)
Use Visual Studio 2022 Community or later. Open the CMake project directly or generate a solution with CMake.
CLion (all platforms)
Open the repository root. CLion auto-detects CMakeLists.txt and configures the project.
What’s in the Manual
This manual will cover all aspects of custom development with fifengine:
-
the compilation of FIFE (Part I)
-
the engine architecture and internals (Part II)
-
developing with FIFE: C++, Python bindings, map format (Part III)
-
contributing: workflow, coding standards, testing, releases (Part IV)
-
tools and reference: dependencies, glossary (Part V)
Related Documentation
-
User Manual — covers game development with FIFE (rendering, model, audio, input, GUI, pathfinding, VFS)
-
C++ API Documentation — generated Doxygen docs
-
Python API Documentation — generated Python API docs
1. Compiling Fifengine
Compiling Fifengine is a complicated and time consuming task. This chapter explains how to setup a compilation environment for Fife.
You’ll find detailed setup steps for fifengine on the operating systems Windows, Linux and Mac.
The individual subchapters have the same structure:
Firstly, we’ll setup an IDE, then the compiler toolchain and additionally needed build-tools.
Secondly, we’ll discuss how to get all the dependencies, either by building them from source or by using pre-build binaries.
Thirdly, we’ll show how to build fifengine itself.
Without further ado, let’s get started.
1.1. Building Fifengine on Windows
1.1.1. Build Environment
Firstly, we need to setup an IDE and several build tools.
1.1.1.1. IDE
The are several good IDEs available, including:
1.1.1.2. Compiler
You need msvc or gcc.
In case you installed MS Visual Studio, then the MSVC compiler is already installed.
1.1.1.3. CMake
Fife uses CMake as build system. The build system generates the build configuration for the project and set the project up for your specific IDE.
1.1.1.4. SWIG
Fife uses Swig as interface generator. Fife itself is written in C++, for being able to access the API from Python, we are wrapping it using Swig.
1.1.1.5. Python
To build the Python extension you need Python. Fife works with Python 3.4+
1.1.2. Dependencies
Fifengine depends on several external libraries.
This is the detailed list.
Our next step is to ensure that all dependencies are installed properly, before you try to build fifengine itself. You have the choice of building the dependencies from source or fetching pre-build, packaged binaries.
1.1.2.1. Using packaged dependencies
The pre-build binaries are build on-the-fly, when building Fifengine on Appveyor. You find MSVC 14 builds here: https://ci.appveyor.com/project/LinuxDonald/fifengine
These builds are also included in our pre-packaged Windows development kit, the Fife-SDK.
The default install location is fifengine-dependencies next to your fifengine source folder.
When you’re using an alternative location, please set the library and include dirs for the dependencies accordingly.
1.1.2.2. Building dependencies from source
You can build the dependencies for Windows using MSVC.
The CMake config file for the dependencies is fifengine\dependencies\CMakeLists.txt.
It includes the individual scripts for fetching and building dependencies.
They are located in the main CMake scripts folder: fifengine\cmake\get-*.cmake.
Let’s configure the dependencies project and then build all dependencies:
cmake dependencies -G "Visual Studio 14" -B../fifengine-dependencies/build
cmake --build ../fifengine-dependencies/build --target ALL_BUILD --config Release
You’ll now find the dependencies the fifengine-dependencies folder:
dir ..\fifengine-dependencies
dir ..\fifengine-dependencies\downloads
dir ..\fifengine-dependencies\includes /s
1.1.3. Building Fifechan
Fifechan is a C++ GUI library that is required as an optional dependency for FIFE. You need to build it from source before building FIFE.
1.1.3.1. Install Dependencies
Download and install the following dependencies:
1.1.3.2. Clone and Build
Open the Developer Command Prompt for Visual Studio, then:
git clone https://github.com/fifengine/fifechan.git
cd fifechan
mkdir _build
cd _build
cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_INSTALL_PREFIX=C:\fifechan ..
cmake --build . --config Release
cmake --install . --config Release
For Debug builds, replace Release with Debug.
1.1.3.3. Using CMake Presets
Fifechan includes CMake presets. To use them:
cmake --preset vc17-x64-windows-rel
cmake --build --preset vc17-x64-windows-rel
cmake --install --preset vc17-x64-windows-rel
1.1.4. Building Fifengine
If you have Python 3 installed you can choose the Version with the command:
With "-DPYTHON_EXECUTABLE=/PATH/TO/PYTHONEXECUTABLE" you can change the Python Version what you want to use. If it is not the System defualt Python Version.
Finally, we can compile Fifengine.
To build Fife, you’ll of course need the Fife source code. You can download a Fife source code package or fetch the latest source using git.
git clone https://github.com/fifengine/fifengine.git && cd fifengine
Configure and build using CMake:
mkdir _build
cd _build
cmake -G "Visual Studio 17 2022" -A x64 ..
cmake --build . --config Release
To specify a custom Python executable, add the -DPYTHON_EXECUTABLE option:
cmake -G "Visual Studio 17 2022" -A x64 -DPYTHON_EXECUTABLE=C:\Python311\python.exe ..
cmake --build . --config Release
To build with the C/C++ library and header files:
cmake -G "Visual Studio 17 2022" -A x64 -Dbuild-library=ON ..
cmake --build . --config Release
For Debug builds, replace Release with Debug.
1.2. Building Fifengine on Linux
This guide will help you build fife on various flavors of linux.
1.2.1. Build Environment
Firstly, we need to setup an IDE and several build tools.
1.2.1.1. IDE
The are several good IDEs available, including:
Now, that you have an IDE installed, you need to setup the required build tools. This includes an compiler of your choice, the build system CMake, the interface generator Swig and Python.
1.2.1.2. Compiler
You can compile fife with gcc or clang.
| We don’t ship a C/C compiler in our Windows SDK. Instructions on how to set up a compiler and build system for C development on Windows can be found [here](https://userbase.kde.org/KDevelop4/Manual/WindowsSetup). |
1.2.1.3. CMake
Fife uses CMake as build system. The build system generates the build configuration for the project and set the project up for your specific IDE.
1.2.1.4. SWIG
Fife uses Swig as interface generator. Fife itself is written in C++, for being able to access the API from Python, we are wrapping it using Swig.
1.2.1.5. Python
To build the Python extension you need Python. Fife works with Python 3.4+
1.2.2. Dependencies
Fife depends on a multitude of external libraries.
Our next step is to ensure that all dependencies are installed properly, before you try to build fifengine itself. You have the choice of building the dependencies from source or fetching pre-build, packaged binaries.
We do not provide a pre-packaged software development kit for Linux.
Additionally, you find more detailed information in the dependencies chapter.
1.2.2.1. Building dependencies from source
| We are working on building the dependencies on the fly. For now we simply use pre-build packages. |
1.2.2.2. Using packaged dependencies
Debian based systems
On debian based systems you can grab all dependencies by installing the following packages:
Python 3:
apt-get install -y build-essential libalsa-ocaml-dev libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev libvorbis-dev libalut-dev python3 python3-dev swig zlib1g-dev libopenal-dev git python3-yaml libxcursor1 libxcursor-dev cmake cmake-data libtinyxml2-dev libpng-dev libglew-dev
Gentoo based systems
Python 3:
emerge --ask --verbose --noreplace libvorbis libogg media-libs/openal libsdl2 sdl2-image sdl2-ttf git pyyaml dev-lang/swig dev-libs/tinyxml2 dev-util/cmake media-libs/glew dev-lang/python3 dev-python/future
Fedora based systems
Python 3:
dnf install git python3 gcc gcc-c++ SDL2 SDL2-static SDL2-devel SDL2_ttf SDL2_ttf-devel SDL2_image SDL2_image-devel libvorbis libvorbis-devel libogg libogg-devel openal-soft openal-soft-devel zlib zlib-devel mesa-libGL mesa-libGL-devel mesa-libGLU mesa-libGLU-devel swig libXcursor libXcursor-devel alsa-lib alsa-lib-devel python-alsa python3-PyYAML cmake tinyxml2-devel libpng libpng-devel fifechan fifechan-devel fifechan-opengl fifechan-opengl-devel fifechan-sdl fifechan-sdl-devel glew glew-devel
Arch Linux based systems
Python 3:
pacman -S sdl2 sdl2_ttf sdl2_image libvorbis libogg openal swig python zlib libgl libpng tinyxml2 python-pillow python-future cmake glew
NOTE that you will also need to install fifechan from source, until it’s available as a package for your distro. Fifechan is in the following distros: Fedora
1.2.3. Building Fifechan
Fifechan is a C++ GUI library that is required as an optional dependency for FIFE. You need to build it from source before building FIFE.
1.2.3.1. Install System Dependencies
Fifechan requires the following dependencies to be installed on your system:
apt-get install -y \
build-essential \
cmake \
ninja-build \
freetype \
libsdl2-dev \
libsdl2-image-dev \
libsdl2-mixer-dev \
libsdl2-ttf-dev \
libglew-dev \
libxcursor-dev \
libx11-dev \
libxext-dev
For testing (optional):
apt-get install -y catch2
1.2.3.2. Clone and Build
git clone https://github.com/fifengine/fifechan.git && cd fifechan
Create a build directory and configure with CMake using a preset or manual configuration:
mkdir -p _build && cd _build
cmake --preset gcc14-x64-linux-rel
cmake --build --preset gcc14-x64-linux-rel
Or manually with CMake:
mkdir -p _build && cd _build
cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
sudo cmake --install .
1.2.3.3. Build with Clang
mkdir -p _build && cd _build
cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
cmake --build .
sudo cmake --install .
1.2.4. Building Fifengine
Finally, we can compile Fifengine.
To build Fife, you’ll of course need the Fife source code. You can download a Fife source code package or fetch the latest source using git.
git clone https://github.com/fifengine/fifengine.git && cd fifengine
If you have only an old version of cmake (2.X) then please do this:
mkdir ../_build; cd ../_build/; cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../fifengine/
instand of: mkdir _build; cd _build; cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
To build fife with Python support only do:
With "-DPYTHON_EXECUTABLE=/PATH/TO/PYTHONEXECUTABLE" you can change the Python Version what you want to use. If it is not the System defualt Python Version.
mkdir _build; cd _build; cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
To build it with Python support only do (with Clang instand of GCC Compiler):
mkdir _build; cd _build; cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
To build fife with Python support and with c/c++ lib and header files do:
mkdir _build; cd _build; cmake -Dbuild-library=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
To build fife with Python support and with c/c++ lib and header files do (with Clang instand of GCC Compiler):
mkdir _build; cd _build; cmake -Dbuild-library=ON -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
after that you can build the project using make and then install it:
make && sudo make install
1.3. Building Fifengine on Mac
1.3.1. Build Environment
Firstly, we need to setup an IDE and several build tools.
1.3.1.1. IDE
The are several good IDEs available, including:
1.3.1.2. Compiler
You can compile fife with clang.
1.3.1.3. CMake
Fife uses CMake as build system. The build system generates the build configuration for the project and set the project up for your specific IDE.
1.3.1.4. SWIG
Fife uses Swig as interface generator. Fife itself is written in C++, for being able to access the API from Python, we are wrapping it using Swig.
1.3.1.5. Python
To build the Python extension you need Python. Fife works with Python 3.4+
1.3.2. Dependencies
Fife depends on a multitude of external libraries.
Our next step is to ensure that all dependencies are installed properly. We do this by either compiling and installing them manually or by fetching and installing pre-compiled binaries.
We do not provide a pre-packaged software development kit for Mac.
Additionally, you find more detailed information in the dependencies chapter.
1.3.2.1. Building dependencies from source
| We are working on building the dependencies on the fly. For now we simply use pre-build packages. |
1.3.2.2. Using packaged dependencies
brew update && brew install swig sdl2 sdl2_image sdl2_ttf freetype openal-soft tinyxml2 glew libvorbis (for python 3 support: python3)
1.3.3. Building Fifechan
Fifechan is a C++ GUI library that is required as an optional dependency for FIFE. You need to build it from source before building FIFE.
1.3.3.1. Install System Dependencies
Install dependencies using Homebrew:
brew install cmake ninja freetype sdl2 sdl2_image sdl2_mixer sdl2_ttf glew
For testing (optional):
brew install catch2
1.3.3.2. Clone and Build
git clone https://github.com/fifengine/fifechan.git && cd fifechan
Create a build directory and configure with CMake using a preset or manual configuration:
mkdir -p _build && cd _build
cmake --preset clang16-x64-osx-rel
cmake --build --preset clang16-x64-osx-rel
Or manually with CMake:
mkdir -p _build && cd _build
cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
sudo cmake --install .
1.3.4. Building Fifengine
Finally, we can compile Fifengine.
To build Fife, you’ll of course need the Fife source code. You can download a Fife source code package or fetch the latest source using git.
git clone https://github.com/fifengine/fifengine.git && cd fifengine
To build fife with Python support only do:
With "-DPYTHON_EXECUTABLE=/PATH/TO/PYTHONEXECUTABLE" you can change the Python Version what you want to use. If it is not the System defualt Python Version.
mkdir _build; cd _build; cmake ../fifengine
To build fife with Python support and with c/c++ lib and header files do:
mkdir _build; cd _build; cmake -Dbuild-library=ON ..
after that you can build the project using make and then install it:
make && sudo make install
1.4. CMake
CMake is a "meta build system" that reads a description of the project written in the CMakeLists.txt files and emits a build system for that project of your choice using one of CMake’s "generators".
This allows CMake to support many different platforms and build tools.
You can run cmake --help to see the list of supported "generators" on your platform.
1.5. CMake Build Types
Several build types are supported.
-
Release
-
Debug
-
RelWithDebInfo
-
MinSizeRel
For the single configuration generators (e.g. "Unix Makefile" and "Visual Studio 12 2013"") you set the build type when invoking cmake by passing -DCMAKE_BUILD_TYPE=<build_type> where <build_type> is one of the build types specified above.
For multi-configuration generators (e.g. Visual Studio) you don’t set the build type when invoking CMake and instead set the build type within Visual Studio itself (by using the dropdown in the top navigation bar).
1.6. CMake configuration options
There are three groups of configuration options:
-
CMake’s own config options: The
CMAKE_*flags allow to declare useful build variables, including locations, environment variables, compiler information and compiler flags. You find more details in the CMake Wiki - Useful Variables. -
Fifengines’s config options:We provide several configuration flags, which allow configuring the fifengine build. They control which subsystems/components of fifengine to build. You find the overview in the CMakeLists file.
-
Config options for finding dependencies: Finally, we have
*_INCLUDEDIR+*_LIBRARY_DIRflags. These are used to set the paths to the headers and lib folder for dependencies.
On the command line options can be passed to cmake using the -D option.
In ccmake and cmake-gui these can be set in the user interface.
|
We are guiding CMake to find the dependencies automatically.
The default location for dependencies is a folder If the dependencies are placed into a folder of your choice, you need to give the paths to each
dependencies to CMake. Either by declaring them on the CLI by using the |
cmake ..\fifengine
|
We are building in a seperate build folder: the |
-G %GENERATOR%
|
You need to specifiy the requested GENERATOR IDE. This is either |
-DCMAKE_PREFIX_PATH="C:\fifesdk\fifengine-dependencies\include"
|
where the includes are |
-DCMAKE_BUILD_TYPE=%CONFIGURATION%
|
Release or Debug |
-DCMAKE_INSTALL_PREFIX="C:\fifesdk\fife-install"
|
the installation folder, after build |
-DPYTHON_INCLUDE_DIR="C:\fifesdk\python\include"
|
helper to find Python |
-DPYTHON_LIBRARY="C:\fifesdk\python\libs\python3.lib"
|
helper to find Python |
-DSWIG_DIR=C:\fifesdk\swig
|
helper to find Swig folder |
-DSWIG_EXECUTABLE=C:\fifesdk\swig\swig.exe
|
helper to find Swig executable |
-DSDL2_INCLUDE_DIR="C:\fifesdk\fifengine-dependencies\include\SDL2"
|
helper to find SDL2 headers |
-DSDL2_LIBRARY_DIR="C:\fifesdk\fifengine-dependencies\lib\x86"
|
helper to find SDL2 library |
-Dbuild-library=ON
|
This build flags enables building the shared library (ON). When disabled (OFF), then only the Python extension is build. |
-DBUILD_SHARED_LIBS=ON
|
This build flag controls, whether to build a shared (ON) or static library (OFF). |
1.7. Running the demos
The demos have their own git repository: https://github.com/fifengine/fifengine-demos
Assuming that you have successfully built fife,
you will be able to change directory to one of the fife demos located in <fifengine-demos> and type: python run.py.
You might also run the demos by double-clicking the run.py file in your file browser. This requires python to be associated with .py files in order to work.
|
1.7.1. Available Demos
| Demo | Description |
|---|---|
rio_de_hola |
The flagship demo. Shows isometric rendering, pathfinding, agent movement, and layered maps. |
pychan_demo |
Demonstrates the PyChan GUI toolkit: buttons, text fields, windows, and layouts. |
fife_test |
Minimal test case for engine initialization and basic map loading. |
1.7.2. Troubleshooting
-
ImportError: No module named fife — FIFE Python bindings are not installed or not on
PYTHONPATH. Build FIFE first and ensure the bindings are accessible. -
SDL2 not found — Install SDL2 development libraries for your platform (see build instructions for your OS).
-
Black screen / no rendering — Verify OpenGL drivers are installed. Try setting
RenderBackend=SDLin the engine settings to use software rendering. -
Segfault on startup — Often caused by mismatched FIFE library and demo versions. Ensure both are from the same commit or release.
1.7.3. Creating a Minimal Project
To create a minimal FIFE project from scratch:
-
Create a directory for your project:
mkdir my-fife-game && cd my-fife-game -
Create
run.pywith minimal engine initialization:import fife settings = fife.Settings() engine = fife.Engine(settings) engine.init() # Your game logic here engine.destroy() -
Create a
settings.xmlfile to configure the engine (see Engine Settings for available options). -
Create an
objects/directory for your game objects and amaps/directory for your map files.
For a complete working example, see the rio_de_hola demo in the fife-demos repository.
|
2. Engine
| This chapter is under development. See the user-manual for detailed API documentation. |
The FIFE engine is the core C++ library that provides all game engine functionality. It handles rendering, audio, input, pathfinding, and the model system.
For game developers using FIFE, see the User Manual for API usage. For engine developers extending FIFE, this chapter covers the internal architecture and extension points.
2.1. Source Code Architecture
This section describes the FIFE engine from a developer’s perspective — how the source is organized, how modules depend on each other, and what build artifacts are produced.
2.1.1. Source Directory Layout
The FIFE repository is organized as follows:
fifengine/
├── engine/
│ ├── core/ # C++ engine core (rendering, model, audio, pathfinding, VFS)
│ │ ├── video/ # Rendering subsystem (backends, renderers, camera)
│ │ ├── model/ # Data model (maps, layers, instances, objects)
│ │ ├── audio/ # Audio subsystem (OpenAL integration)
│ │ ├── pathfinder/ # Pathfinding algorithms (A*, cell-based routing)
│ │ ├── vfs/ # Virtual filesystem (asset loading, archives)
│ │ ├── eventchannel/ # Event system (input, timers, listeners)
│ │ ├── gui/ # FifeChan GUI integration
│ │ └── util/ # Shared utilities (logger, settings, math)
│ ├── python/ # SWIG interface files and Python-specific wrappers
│ │ └── fife/ # PyChan and Python extension module
│ └── swigwraps/ # SWIG .i interface files for each subsystem
├── dependencies/ # Dependency build scripts (CMakeLists.txt, get-*.cmake)
├── cmake/ # CMake modules and helper scripts
├── doc/ # Generated documentation output
└── tests/ # Test suite
2.1.2. Module Boundaries
The engine is divided into loosely coupled modules within engine/core/. Each module has a clear responsibility:
| Module | Responsibility |
|---|---|
video |
Rendering pipeline, backend abstraction (SDL2/OpenGL), camera, renderers |
model |
Game world representation: maps, layers, instances, objects, coordinates |
audio |
Sound playback via OpenAL, sound clip management |
pathfinder |
Cell-based pathfinding (A*, graph algorithms), route planning |
vfs |
Virtual filesystem abstraction for loading assets from disk or archives |
eventchannel |
Event dispatching, input handling, listener registration |
gui |
FifeChan widget integration, PyChan Python wrapper |
util |
Logger, settings parser, math utilities, exception handling |
Modules communicate through well-defined interfaces. The model module does not depend on video, and pathfinder does not depend on audio. Cross-cutting concerns (logging, settings) are in util and used by all modules.
2.1.3. Layer Stack
From a code perspective, the engine is layered:
Game Client (Python or C++)
│
▼
┌───────────────────────────────────┐
│ SWIG Python Bindings │ ← Generated from .i files in engine/swigwraps/
├───────────────────────────────────┤
│ PyChan (Python FifeChan Wrapper) │ ← engine/python/fife/
├───────────────────────────────────┤
│ FIFE Core (C++) │ ← engine/core/
├───────────────────────────────────┤
│ FifeChan (C++ GUI Library) │ ← External dependency
├───────────────────────────────────┤
│ SDL2 (Graphics, Input, Audio) │ ← External dependency
└───────────────────────────────────┘
Each layer only depends on the layer below it. Game code can call either the Python API (via SWIG) or the native C++ API directly.
2.1.4. Build Artifacts
Depending on CMake options, the build produces:
| Artifact | Description | CMake Option |
|---|---|---|
|
Shared C++ library for native game clients |
|
|
Python extension module (SWIG-generated wrapper) |
Default (always built) |
|
FifeChan GUI library (external dependency) |
Built separately |
When -Dbuild-library=OFF, only the Python extension is built (linked statically against the engine core).
2.1.5. Threading Model
FIFE uses a single-threaded model for the main game loop:
-
The game client calls
engine.initializePump()once at startup -
Each frame, the client calls
engine.pump()which processes:-
Input events
-
Model updates (instance logic, animation ticks)
-
Pathfinding requests (queued, processed incrementally)
-
Rendering
-
-
The client calls
engine.finalizePump()on shutdown
Pathfinding is the only operation that can be offloaded to a background thread (via RoutePather::setAsync(true)), but results must be consumed on the main thread.
| The engine is not thread-safe. All API calls must originate from the thread that created the engine instance. |
2.1.6. Memory Ownership
FIFE follows these ownership patterns:
-
Engine owns subsystems —
Engineowns and manages the lifecycle of all subsystems (renderer, model, audio, etc.). Do not delete subsystem pointers. -
Model owns maps —
Modelowns allMapobjects. Maps own theirLayerobjects, and layers own theirInstanceobjects. UsedeleteMap(),deleteLayers(),deleteInstance()to remove. -
Instances own references — An
Instancedoes not own itsObjecttemplate. Objects are managed by the model’s object registry. -
SWIG manages Python wrappers — SWIG generates reference-counted Python wrappers. The Python garbage collector releases them when they go out of scope. Avoid holding raw C pointers across Python/C boundaries.
-
Resource managers own cached assets —
ImageManager,AnimationManager, andSoundClipManagercache loaded resources. Release unused resources explicitly to free memory.
2.2. Engine Internals & Extension Points
This section covers how to extend and modify the FIFE engine internals.
2.2.1. Adding a New Engine Subsystem
To add a new subsystem to the engine:
-
Create a new directory under
engine/core/(e.g.,engine/core/mysubsystem/). -
Define a header with a class inheriting from no base (subsystems are standalone).
-
Register the subsystem in
Engine::createSubsystems()inengine/core/engine.cpp. -
Add initialization in
Engine::init()and cleanup inEngine::destroy(). -
If the subsystem needs configuration, add entries to
EngineSettings. -
Create a SWIG interface file in
engine/swigwraps/to expose it to Python.
2.2.2. SWIG Binding Generation
FIFE uses SWIG to generate Python bindings from C++ headers.
2.2.3. Interface Files
SWIG interface files (.i) are located in engine/swigwraps/. Each file corresponds to a subsystem:
engine/swigwraps/
├── fife.i # Main module definition
├── model.i # Model subsystem bindings
├── video.i # Video subsystem bindings
├── audio.i # Audio subsystem bindings
├── pathfinder.i # Pathfinder subsystem bindings
├── vfs.i # VFS subsystem bindings
├── eventchannel.i # Event channel bindings
├── util.i # Utility bindings
└── gui.i # GUI/PyChan bindings
2.2.4. Exposing New C++ Methods
To expose a new C++ method to Python:
-
Add the method declaration to the C++ header (e.g.,
engine/core/model/mymethod.h). -
Add a
%includedirective to the corresponding.ifile (e.g.,model.i):%include "model/mymethod.h" -
Rebuild the project. SWIG regenerates the Python wrapper automatically.
2.2.5. Memory Ownership in SWIG
SWIG-generated wrappers use reference counting. Key rules:
-
Objects returned by value are copied into Python-owned memory.
-
Objects returned by pointer are managed by C++ unless
%newobjectis specified. -
Use
%newobjectwhen Python should take ownership and delete the object:%newobject Model::createMap;
2.2.6. PyChan Architecture
PyChan is a Pythonic wrapper around FifeChan, providing a widget-based GUI system.
2.2.7. Component Hierarchy
PyChan (Python)
│
├── Widget base class (common properties: position, size, name)
│
├── Container widgets: HBox, VBox, FlowContainer, ScrollArea
├── Content widgets: Label, Icon, Button, CheckBox
├── Input widgets: TextField, Slider, DropDown
└── Top-level: Window, GuiManager
PyChan widgets wrap FifeChan widgets. The GuiManager is the root container that manages focus, input routing, and rendering.
2.2.8. Key Classes
| Class | Purpose |
|---|---|
|
Top-level container; manages widget tree and event routing |
|
Base class; provides position, size, visibility, name, style |
|
Draggable, resizable container with title bar |
|
Clickable button with label and callback |
2.2.9. Resource Manager Internals
FIFE uses manager classes to cache and lazily load resources:
| Manager | Resource Type | Caching Strategy |
|---|---|---|
|
Textures and sprites |
LRU cache with configurable max size |
|
Animation sequences |
Loaded on demand, retained until explicitly released |
|
Audio clips |
Loaded on first playback, cached until release |
Resource managers follow a common pattern:
-
Request a resource by ID:
imageManager→get(resourceId) -
Manager checks cache — if found, returns cached resource
-
If not found, loads from VFS, caches, and returns
-
Call
release(resourceId)to free from cache
2.2.10. Event/Listener Pattern
FIFE uses an observer pattern for events:
class MyListener : public fife::MouseListener {
public:
void mousePressed(fife::MouseEvent& evt) override {
// Handle mouse press
}
};
// Register listener
eventManager->addMouseListener(myListener);
Available listener types: MouseListener, KeyListener, WidgetListener, TimeEventControllerListener.
2.2.11. Renderer Pipeline
Renderers are registered and executed each frame in order:
-
Camera queries visible instances from the model
-
Each registered renderer processes instances (grid, generic, cell, coordinate)
-
Renderers are sorted by priority (lower values render first)
-
Each renderer calls
setColor/getImageon instances and draws to the camera’s render target
To register a custom renderer, subclass RendererBase and call View::addRenderer().
2.2.12. Logging System
The logging system supports multiple modules and levels:
fife::Log::log(fife::LOG_LEVEL_DEBUG, "MyModule", "Debug message");
Levels: LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR
Modules can be filtered at runtime via Log::setModuleLogLevel().
2.2.12.1. C++ Logging Macros
When writing C++ code, always use the provided log macros defined in
engine/core/modules.h:
FL_DBG(module, msg) // Debug level
FL_LOG(module, msg) // Informational level
FL_WARN(module, msg) // Warning level
FL_ERR(module, msg) // Error level
FL_PANIC(module, msg) // Panic level (causes abort)
Modules are defined in <FIFE>/engine/core/modules.h. Always use the correct
log module when writing to the log.
2.2.13. XML Settings to EngineSettings
The XML settings file maps directly to EngineSettings:
<Settings>
<Screen width="1024" height="768" />
<Render backend="OpenGL" />
</Settings>
Each XML element maps to a setter in EngineSettings:
* <Screen width="1024"> → settings.setScreenWidth(1024)
* <Render backend="OpenGL"> → settings.setRenderBackend("OpenGL")
2.2.14. VFS Implementation
The Virtual File System (VFS) abstracts file access:
-
Sources are registered:
vfs.addSource(new DirectorySource("assets/")) -
When loading a file, VFS searches sources in registration order
-
Archives (ZIP, etc.) are mounted as sources and accessed transparently
-
The
ImageLoader,MapLoader, and other loaders use VFS for all I/O
2.2.15. Cell Cache and Pathfinder
The pathfinder uses a cell cache for efficient lookups:
-
Each layer has a
CellCachestoring walkability, cost, and blocking info -
When a route is requested, the pathfinder queries the
CellCache -
A* search runs on the cell graph (edges defined by
CellGridgeometry) -
Results are cached in the
Routeobject until invalidated
2.3. C++ Development Patterns
This section covers common patterns for extending and developing with the FIFE engine in C++.
2.3.1. Extending FIFE Classes
FIFE uses virtual methods and interfaces for extensibility. Common patterns:
-
Subclass and override — Create a derived class and override virtual methods (e.g.,
RendererBase,MouseListener). -
Register your implementation — Pass your subclass to the appropriate manager or subsystem.
-
Use existing patterns — Follow the observer/listener pattern for events, the manager pattern for resources.
2.3.2. Implementing a Custom Renderer
To create a custom renderer:
-
Subclass
fife::RendererBase:class MyRenderer : public fife::RendererBase { public: MyRenderer() : fife::RendererBase("MyRenderer") {} void render(fife::RenderBackend& backend, fife::Layer* layer) override { // Custom rendering logic } }; -
Register with the view:
view->addRenderer(new MyRenderer());
2.3.3. Adding a New Pathfinder Algorithm
-
Create a new class in
engine/core/pathfinder/inheriting from the pathfinder interface. -
Implement the search method (A*, Dijkstra, etc.).
-
Register in the pathfinder router so it can be selected via
RoutePather::setPathingStrategy().
2.3.4. Adding a New Resource Type
-
Create a resource class (e.g.,
MyResource) with load/release methods. -
Create a manager class (
MyResourceManager) following the pattern ofImageManager. -
Register the manager in the engine initialization.
2.3.5. Key Internal Classes
| Class | Purpose |
|---|---|
|
Entry point; owns all subsystems, manages lifecycle |
|
Game world container; owns maps, layers, instances |
|
A single game map; owns layers and cameras |
|
A grid of instances; provides spatial queries |
|
A placed object in the world; has position, rotation, animation |
|
Template/archetype defining instance properties |
|
Base class for all renderers |
|
Manages cameras and renderer pipeline |
For the complete API, see the C++ API Documentation.
2.4. Python Bindings & SWIG Workflow
This section explains how the Python bindings are generated and how to work with them as an engine developer.
2.4.1. SWIG Interface File Structure
SWIG interface files (.i) define which C++ declarations are exposed to Python. Each file follows this structure:
%module fife
%{
#include "core/model/model.h"
#include "core/video/renderbackend.h"
// ... other headers
%}
%include "core/model/model.h"
%include "core/video/renderbackend.h"
// ... other includes
The %{ … %} block contains C++ code inserted into the generated wrapper (typically #include directives). The %include directives tell SWIG which headers to wrap.
2.4.2. Exposing New C++ Methods
To expose a new C++ method to Python:
-
Add the method to the C++ header with proper documentation.
-
Find the corresponding
.ifile inengine/swigwraps/. -
Add a
%includefor the header if not already present:%include "core/mysubsystem/mynewclass.h" -
If the method returns a newly allocated object, add
%newobject:%newobject Model::createMap; -
Rebuild the project. CMake automatically regenerates the Python wrapper.
2.4.4. Memory Ownership
SWIG generates reference-counted Python wrappers. Key rules:
-
Objects returned by value are copied — Python owns the copy.
-
Objects returned by pointer are owned by C++ unless
%newobjectis specified. -
Holding a C++ pointer after the owning object is deleted causes undefined behavior.
2.4.5. Method Naming
SWIG converts C++ method names to Python conventions:
* getSomething() → getSomething() (unchanged by default)
* Use %rename to customize: %rename("get_something") getSomething;
2.4.6. Enum Handling
C++ enums become Python classes with integer values:
# Access enum values
render_backend = fife.RenderBackendOpenGL
2.4.7. List vs Vector
std::vector<T> is automatically converted to Python lists. Return types of std::vector<T> become Python lists.
2.4.8. Writing Python Extensions
To write a Python extension that integrates with the engine:
-
Import the FIFE module:
import fife -
Use the engine API as documented in the Python API Documentation.
-
Register callbacks and event listeners using the provided interfaces.
2.4.9. PyChan for Engine Developers
PyChan wraps FifeChan widgets for Python. Engine developers working on PyChan:
-
Source location:
engine/python/fife/extensions/pychan/ -
Each widget class wraps a corresponding C++
fife::fifechan::Widgetsubclass -
Properties are exposed via SWIG getters/setters
-
Signal/slot connections use Python callbacks
| For game developer usage of PyChan, see the User Manual - GUI chapter. |
2.5. Map Format Internals
This section documents the FIFE map format from a code perspective — how maps are structured, loaded, and extended.
2.5.1. XML Map File Schema
FIFE maps are stored as XML files. The basic structure:
<Map id="mymap" version="1">
<Metadata>
<Author name="developer" />
</Metadata>
<Settings>
<Setting name="some_setting" type="int">42</Setting>
</Settings>
<Elevations>
<Elevation id="0">
<Layers>
<Layer id="ground_layer" grid_type="square" pathing="cell_edges_only">
<Instances>
<Instance object="tree" x="5" y="3" />
</Instances>
</Layer>
</Layers>
</Elevation>
</Elevations>
</Map>
2.5.2. Object/Atlas XML Format
Objects are defined in separate XML files and loaded by ObjectLoader:
<assets>
<object id="tree" namespace="trees">
<image source="tree.png" />
<pivot x="0.5" y="1.0" />
<blocking block="true" />
</object>
</assets>
Image atlases group multiple images:
<atlas image="spritesheet.png">
<image x="0" y="0" width="32" height="32" name="frame_0" />
<image x="32" y="0" width="32" height="32" name="frame_1" />
</atlas>
2.5.3. MapLoader and MapSaver
The MapLoader class handles loading maps from XML:
-
Parses the XML using TinyXML2
-
Creates
Mapobject with given ID -
Iterates
<Elevation>elements, creating elevations -
For each elevation, iterates
<Layer>elements, creating layers with specified grid type -
For each layer, iterates
<Instance>elements, creating instances by resolving object references
The MapSaver class writes maps back to XML, serializing the in-memory model.
2.5.4. Extending the Map Format
To add custom data to the map:
-
Add a new XML element under
<Map>,<Elevation>, or<Layer>. -
Modify
MapLoaderto parse the new element. -
Store the parsed data in the appropriate model object (e.g.,
Map::setCustomData()). -
Modify
MapSaverto serialize the custom data back.
| For user-facing map documentation, see the User Manual - Working with Maps. |
2.6. Overview Diagram
Failed to generate image: Could not load Ditaa. Either require 'asciidoctor-diagram-ditaamini' or specify the location of the Ditaa JAR(s) using the 'DIAGRAM_DITAA_CLASSPATH' environment variable.
+------------------------------------+
| |
| Simple DirectMedia Layer (SDL2) |
| |
| http://www.libsdl.org/ |
| |
| is a cross-platform development |
| library designed to provide low |
| level access to audio, keyboard, |
| mouse, joystick, and graphics |
| hardware via OpenGL and Direct3D. |
| |
+------------------------------------+
^
|
|
v
+----------------------------------------+
| |
| Fifechan |
| |
| https://github.com/fifengine/fifechan |
| |
| is a {cpp} GUI library designed for |
| games. It comes with a standard set |
| of 'widgets' and can use several |
| different objects for displaying |
| graphics and capturing user input. |
| |
+----------------------------------------+
^
|
|
v
+--------------------------------------------------------------+
| |
| FIFE |
| |
| https://github.com/fifengine/fifengine |
| |
| is a multi-platform isometric game engine |
| |
+--------------------------------------------+ |
| | |
| PyChan | |
| | |
| part of FIFE codebase | |
| | |
| is a Pythonic Fifechan Wrapper | |
| | |
+--------------------------------------------------------------+
| | |
| Pythonic Fife API | Native {cpp} API |
| | |
| created by SWIG | |
| | |
+--------------------------------------------------------------+
^ ^
| |
| |
v v
+----------------------------------+ +------------------------------------+
| | | |
| Game Client | | Game Client |
| written in Python | | written in {cpp} |
| | | |
+----------------------------------+ +------------------------------------+
2.7. Engine Settings
NOTE: This information is Python specific
When a Python program wants to use FIFE engine, it has to provide some basic engine settings to FIFE.
This is done by writing the settings to a xml file and let FIFE know the file name.
FIFE loads the settings from that file.
If no file is given, FIFE searches for the "settings.xml" file in the current directory.
This section describes the different settings that can be set in settings.xml file.
| For runtime configuration in game code, see the User Manual - Runtime Configuration. |
2.7.1. Basic settings
Every program has to give some basic settings.
These are FullScreen, PlaySounds, ScreenResolution, RenderBackend and Lighting.
If any one of them is excluded, FIFE cannot load the program and will generate error:
AttributeError: 'NoneType' object has no attribute 'findChildByName' .
So, the basic xml file to load FIFE by the client looks like this:
<?xml version='1.0' encoding='UTF-8'?>
<Settings>
<Module name="FIFE">
<Setting name="FullScreen" type="bool"> False </Setting>
<Setting name="PlaySounds" type="bool"> True </Setting>
<Setting name="RenderBackend" type="str"> OpenGL </Setting>
<Setting name="ScreenResolution" type="str">1024x768</Setting>
<Setting name="Lighting" type="int"> 0 </Setting>
</Module>
</Settings>
2.7.2. C++ Usage
When using the C++ API directly, settings are configured programmatically:
fife::EngineSettings settings;
settings.setScreenWidth(1024);
settings.setScreenHeight(768);
settings.setFullScreen(false);
settings.setRenderBackend("OpenGL");
settings.setPlaySounds(true);
fife::Engine engine(settings);
engine.init();
2.7.3. Additional Settings
Apart from these basic settings, other settings are also possible.
All these settings are given below with a brief description attached to them below:
2.7.3.1. Window Settings
- WindowTitle
-
This is a string type variable. The value given here, will be shown as the window title. Default:
"FIFE" - WindowIcon
-
An window icon can be set. This variable contains the path of the icon. Default: none
- ScreenResolution
-
A good number of screen resolutions are available. The default settings are:
640x480,800x600,1024x768,1280x800,1440x900. Default:1024x768 - FullScreen
-
This is a boolean variable. It can get one of the two values
TrueorFalse. Default:False
2.7.3.2. Graphics Settings
- RenderBackend
-
Currently, two backend renderers are available in FIFE. One is OpenGL and the other is SDL. Default:
"OpenGL" - Lighting
-
FIFE supports three lighting models currently. Those are denoted by 0 (simple),1 (image) and 2 (animation). Any value greater than 2 throws an exception later. Default:
0 - BitsPerPixel
-
This field can only have four possible values:
0,16,24and32. Default:0(use desktop depth) - SDLRemoveFakeAlpha
-
This is a setting if somebody uses SDL as the renderer. It is not used anymore probably. Default:
False - ColorKeyEnabled
-
It is a boolean variable for setting color key. Default:
False - ColorKey
-
A string which denotes the rgb value of the color key comma seperated (r,g,b). Default:
"255,0,255" - GLCompressImages
-
Enables or Disables image compression in the OpenGL renderer. Possible values are
True' or `False. Default:False - GLUseFramebuffer
-
A boolean variable to enable or disable the use of the FBO. This is valid only if you are using the OpenGL renderer. Possible values are
TrueorFalse. Default:False - GLUseNPOT
-
A boolean variable to enable or disable the use of non power-of-two textures. This is valid only if you are using the OpenGL renderer. If this is set to False the OpenGL renderer will automatically pad NPOT textures to make them POT. Possible values are
TrueorFalse. Default:False
2.7.3.3. Sound Settings
- PlaySounds
-
Another boolean variable. Giving it 'True' value keeps the sound on. Default:
True - InitialVolume
-
Initially volume is a double value. It cannot contain any negative value and can never exceed the constant MAXIMUM_VOLUME which is 10.0 by the value. Default:
5.0
2.7.3.4. Input Settings
- MouseSensitivity
-
This is a Float value in the range of -0.99 (the slowest) and 10.0 (the fastest) Default:
0.0 - MouseAcceleration
-
Boolean variable.
Trueenables mouse acceleration,Falsedisables it. Default:False
2.7.3.5. Font Settings
- Font
-
This is a string containing the path to the font file. Default: none
- FontGlyphs
-
FontGlyphs are the characters that are defined in image fonts. These fonts are loaded directly from an image file and not from the ttf. FontGlyphs is of string type. All of the Font Glyphs should be given here with exactly same order they are present in the image file. Default: none
- DefaultFontSize
-
We can assign a default font size here. If nothing is mentioned the default font size is 8. Default:
8
2.7.3.6. Logging settings
Log manager provides convenient apis to access engine logging functionality.
Log targets can be set individually (prompt, file).
Things like visible modules can be adjusted through log manager.
- LogModules
-
LogModules sets the modules that we need to log. There are a lot of modules that can be logged, e.g.: controller, video, audio, script etc. Write the module names semicolon seperated. Default: all modules
- LogToPrompt
-
Tells the LogManager whether LogToPrompt should be set. If it is set to 1, log should be seen in the terminal or prompt. Default:
1 - LogToFile
-
Same as LogToPrompt, but here log is written to a file. Default name of the file is
fife.log. Default:0 - LogLevelFilter
-
Loglevel is used to set a treshold for output messages and related filter. There are four levels: LEVEL_DEBUG = 0, LEVEL_LOG = 1, LEVEL_WARN = 2, LEVEL_ERROR = 3, LEVEL_PANIC = 4. For example, in case log message has LEVEL_WARN, but the filter treshold is LEVEL_ERROR, log message is not outputted. Be sure to use LEVEL_PANIC, because it causes a program abort. Default:
0(LEVEL_DEBUG)
2.7.4. Miscellaneous settings
- PychanDebug
-
Boolean variable. PychanDebug enables debug output for the pychan extension. If it is on, a lot of new debugging texts can be seen in the terminal. Default:
False
3. Contributing
Interested in fife and want to help out? Do you see something that needs improving? Better yet, do you have a solution to one of our open issues?
You can support the project in all sorts of areas and we would graciously accept any contributions you have to offer! Please don’t hesitate, if you’ve got an awesome idea to throw into FIFE.
The best part about contributing to an open source project is you get the satisfaction of improving a project, not to mention full recognition for your work! It might help out on that next job application!
3.1. Help wanted…
This is an open source project and developers are contributing on their own time. For this reason we are constantly looking for help.
|
We are looking for:
|
We are in great need for all skill levels of developers to help with our C++ and Python extensions. There is work in just about any field you could imagine, from tool development, to OpenGL eye candy, to ear popping sound effects, to demo game development. You name it, we need it. Are you new to coding but want to learn? Are you an experienced coder looking for a project to fill that void in your life? This is the project for you!
Currently our website is lacking a certain POW. It needs to be re-done in the worst way. We are completely open to your ideas as far as the backend goes. There is a template to start from here. You could either make some templates for our forums and blog or throw the whole thing out and surprise us with something else! It’s gotta look amazing to attract as much attention as possible!
There is a bunch of work that needs to be done here. Our Windows installer needs work, our development kit needs updating, release packaging needs to be automated, the list is endless really. Currently we package every release by hand and this a tedious task so any help in this department would be great!
What project doesn’t need an artist or two? If you have some artistic skills and are looking for a project, look no further! We have several demos that would benefit from some new art (tilesets, gui art, icons, etc etc), not to mention our website!
As they say, good documentation makes a project. This is one department, where it’s difficult to find people to volunteer their time to help out. Any time you can spend documenting fife or helping with tutorials would definitely help make fife even better!
3.2. Workflow
Here’s the most direct way to get your work merged into the project:
-
Fork the project.
-
Clone down your fork (
git clone git://github.com/<username>/fifengine.git). -
Create a topic branch to contain your change (
git checkout -b my_awesome_feature). -
Hack away.
-
If necessary, rebase your commits into logical chunks, without errors.
-
Push the branch up (
git push origin my_awesome_feature). -
Create a pull request against fifengine/fifengine and describe what your change does and the why you think it should be merged.
| Please follow the [[C++ Coding Standards|coding-standards]] or [[Python Coding Standards|Python-coding-standards]] when modifying code. |
3.3. Gotchas
-
Try to keep your patch(es) based from the latest commit on fifengine/fifengine. The easier it is to apply your work, the less work the maintainers have to do, which is always a good thing.
-
Please don’t tag your GitHub issue with [fix], [feature], etc. The maintainers actively read the issues and will label it once they come across it.
3.4. Finally…
Thanks for helping us! We look forward to any contributions you make to help improve FIFE!
3.5. Working with Git
Need help with Github? Make sure to check the great Github Help Center!
Check out some very good git documentation here (including a cheat sheet): http://git-scm.com/docs
3.5.1. Basic git
3.5.1.1. Setting up your git environment
The first thing you should do when you first start running git is to set up some local variables.
Your name and email are very important as they will be part of every commit you make!
git config --global user.name "Your Name" git config --global user.email your.email@gmail.com
3.5.1.2. Clone remote repository
To clone the fifengine repo with URL https://github.com/fifengine/fifengine.git in a specific directory on your machine
git clone https://github.com/fifengine/fifengine.git /path/to/your/projects/
A folder fifengine/ will be created at that location.
3.5.1.3. Update your local repository clone
Execute git pull in the fifengine/ folder.
3.5.2. Commit and Push
Users locally commit their changes to their working copy.
When they are happy with the outcome, they share these commits by pushing them to the remote server.
You need to either commit every change you did to your clone or select the files you want to update with the commit.
This is, amongst others, done with git add.
3.5.3. Examples
Add the changes in the two files export.h / module.h, move the index (of a file without changes) and remove a file as well:
git add engine/core/export.h engine/core/modules.h git mv somefile.cpp newfile.cpp git rm somefile.h
git rm also removes your local copy of that file! You can use the flag -- cached to prevent this.
Now you can use git status to check of everything fits what you want to commit.
3.5.4. Commit
If so, run git commit
and $EDITOR opens up, asking you for a commit message. When you save this file (and it’s not empty), the commit is executed.
GitHub has a blog post about commit message guidelines. See also this very helpful resource.
After that, you can push your changes to the remote repository with git push origin foo if you worked on the branch foo.
Normally you will use git push origin master.
3.5.5. Undo
Edit your most recent, local commit
Just work like you would do with your regular next commit (edit files, git add and so on). When you’re done, type git commit --am and edit the old commit message to fit the appended additions as well.
This should only be used if you are sure that nobody worked on anything in the meantime!
Move to the most recent pushed commit
git reset --hard HEAD~1
Moving to any commit in general
Browse git log for the ID of the last commit you want to keep, removing every newer change. Then (with that ID) use
git reset --hard VERYLONGCOMMITSHA1
Most of the time git revert is what you are looking for.
It does a better job in reverting pushed commits (the two commits will be kept in the project history).
3.5.6. Branches and Merging
Branches are what makes git awesome! They are easy, fast and incredibly useful for distributed development.
Check which branch you are currently on, show all available branches
git branch
Change to another branch
git checkout origin/development
Track a remote branch
git branch -t development origin/development
Create new branch named foo
git checkout -b foo
Delete the branch named foo
git branch -d foo
If the branch was not yet merged, use -D instead of -d.
Try to merge the branch foo into your current branch
git pull . foo
Note that this will create conflict markers in each file where auto-merging is not possible.
You will need to resolve these conflicts manually — there are several tools to do so, see git mergetool.
When ready, you need to commit the resolved files.
The commit message will automatically indicate what kind of conflicts we had.
3.5.7. Patches and Diffs
If you are familiar enough with git, you may of course also customize the options given to the following. This is by all means only a recommendation and no rule to strictly follow.
Generate files containing the two most recent commits
After committing all your changes to a freshly-pulled repo, use
git format-patch -M -B -2
Where -4 instead of -2 would create patch files for the last four commits.
Applying such a file called 0001-user.patch is done using
git am 0001-user.patch
Note that the Unix tool patch does not need to support patch file renaming, so git am is the preferred way to apply patches.
Useful flags might be --resolve.
-M -B handles renaming correctly to create smaller patch files, but this will then only be recognized by git (no unified patch anymore).
3.5.8. Committing patches of other authors
To correctly display who did what in our history, please use the following flags to git commit:
git commit --author "Author Name <email@example.com>"
If you already committed the files and now remembered you need to fix the author, use git commit --amend and proceed as above.
This will edit the newest commit instead of creating a new one.
This is especially important for artists, who otherwise might not get proper credits. Ask them under which name and address they’d like to appear, then use that name consistently as Author Name.
3.5.9. Bughunting and History
Look up who introduced what in <path>
git blame <path>
git gui blame <path>
Check what happened in your repo
Use git log, git show, or git diff.
Find out which commit(s) cause a bug
Start with
git bisect good <tag/SHA where everything works>`
and
git bisect bad <tag/SHA where bug occurs>
Then continue to run the bisection with either entering git bisect good,
if the bug does not show up or git bisect bad if it does.
Repeating that, you will be presented a suspicious commit in the end: investigate there!
4. Coding standards
We have a set of quite detailed coding standards that have been followed for some time.
4.1. Input file formats
FIFE’s accepted input file format is XML. The XML format should be used when describing data (metadata). Any new or existing functionality (like font file definitions) should also use the XML format.
4.2. C++ Coding Standards
The following document describes our C++ coding standard.
4.2.1. Files
-
Headers files end with
.h -
Source files end with
.cpp -
Only one class per h/cpp file. (With a exception for classes that are extremely simple and clearly belong together.)
-
The files should be named after the (main)class they implement, but all in lowercase.
4.2.2. Conventions
4.2.2.1. Abbreviations and capitol letters
We use a mixture of upper and lower camel case (described below). There are some cases where you would be tempted to use to capitol letters together. This should be avoided! When using abbreviations in your variable or class names always capitalize the first letter of the abbreviation and lower-case for the rest.
class ColorRgb8;
class Dat1;
class Vfs;
class GlImage;
class SdlImage;
class GuiChanManager;
4.2.3. Classes
4.2.3.1. General guidelines
-
Name the class after what it is. If you can’t think of what it is that is a clue you have not thought through the design well enough.
-
Compound names of over three words are a clue your design may be confusing various entities in your system. Revisit your design. Try a CRC card session to see if your objects have more responsibilities than they should.
-
Avoid the temptation of bringing the name of the class a class derives from into the derived class’s name. A class should stand on its own. It doesn’t matter what it derives from.
-
Suffixes are sometimes helpful. For example, if your system uses agents then naming something DownloadAgent conveys real information.
4.2.3.2. Class names
-
First character in a name is upper case
-
Use upper case letters as word separators, lower case for the rest of a word
-
No underscores:
_ -
Abstract classes should start with an
I
Also known as "upper camel case". See the Camel Case article at wikipedia.
class MapView;
class IResourceManager;
4.2.3.3. Attribute/Member names
-
Start with a
m_ -
Should not contain any more underscores
-
First word is lower case, the rest start with an upper case letter
RenderBackend* m_renderBackend;
uint16_t m_frameLimit;
std::string m_windowTitle;
This is also known as "lower camel case". See the Camel Case document at wikipedia.
4.2.4. Functions/Methods
4.2.4.1. General guidelines
-
Keep your functions simple.
-
Small functions that should be inlined go to the header file but after the class.
-
Use default parameters instead of inlined overloaded functions if you don’t have a reason not to do so.
so don’t write:
inline void doSomething() { // Wrong
doSomething(0);
}
void doSomething () {
....
}
write:
void doSomething(int32_t x = 0) { // Correct
....
}
4.2.5. Function/Method names
-
Use the same rules as for class names except the first letter should be lower case!
uint8_t getBitsPerPixel() const;
bool isFullScreen() const;
4.2.6. Variables and parameters
4.2.6.1. General guidelines
-
Don’t use global variables.
-
Do not put data definitions in header files.
-
It’s bad magic to have space consuming code silently inserted through the innocent use of header files.
-
It’s not common practice to define variables in the header file so it will not occur to developers to look for this when there are problems.
-
Consider defining the variable once in a .cpp file and use an extern statement to reference it.
-
Consider using a singleton for access to the data.
-
-
Don’t abuse the singleton objects so that they become global variable repositories. If you can’t access a variable easily from where you are you probably shouldn’t be accessing it from there. This is a rule of thumb, not to be enforced strictly.
-
Declare 1 variable on each line.
int32_t x, y, z; // Wrong
int32_t x; // Correct
int32_t y;
int32_t z;
-
Align variable declarations as shown. This makes the code more readable.
int32_t someVar1;
DWORD someVar2;
std::string idSting;
-
Always initialize variables, and when initializing groups of variables align the code as shown.
someVar1 = 0;
someVar2 = 0;
idString = "";
-
When declaring pointers or references, the * or & is placed beside the type, not the variable name
int32_t* intPointer;
int32_t& intReference;
-
Use native types wherever possible. It is not necessary to "optimize" a loop counter by making it a uint8_t. Ideally, the use of such types would be restricted to three types of places:
-
dealing with saving or loading the data (e.g. serialization/de-serialization routines)
-
transmitting data over a network
-
interfacing with external libraries, if those libraries absolutely insist.
-
4.2.6.2. Variable and parameter names
-
Parameter and local variables have no prefix and start with a lowercase letter.
-
Use capitol letters as word separators.
-
Variables and parameters should not contain underscores.
-
Include units in Names. If a variable represents time, weight, or some other unit then include the unit in the name so developers can more easily spot problems.
//Example variable and parameter names
IEngineChangeListener changeListener;
std::string characterId;
//Including units in the name
uint32_t timeoutMsecs;
uint32_t myWeightLbs;
4.2.7. Types
4.2.7.1. Integer types
-
At all times use types as defined in the C99 Standard Library
| Specifier | Equivalent on 64 bit platform | Equivalent on 32 bit platform | Signing | Bits | Bytes |
|---|---|---|---|---|---|
int8_t |
signed char |
signed char |
Signed |
8 |
1 |
uint8_t |
unsigned char |
unsigned char |
Unsigned |
8 |
1 |
int16_t |
short |
short |
Signed |
16 |
2 |
uint16_t |
unsigned short |
unsigned short |
Unsigned |
16 |
2 |
int32_t |
int |
int or long |
Signed |
32 |
4 |
uint32_t |
unsigned int |
unsigned int or unsigned long |
Unsigned |
32 |
4 |
int64_t |
long |
long long |
Signed |
64 |
8 |
uint64_t |
unsigned long |
unsigned long long |
Unsigned |
64 |
8 |
4.2.7.2. Type Safety
-
Don’t use a #define when an enum or
static const int32_tis also possible. -
Do not use the C-style casts; instead use
static_cast,dynamic_castandreinterpret_cast(if really necessary).
4.2.7.3. Const Correctness
-
Be const correct. See: http://www.parashift.com/c++-faq-lite/const-correctness.html
-
Avoid
const_cast.
4.2.7.4. Magic Numbers
Magic numbers are numbers that are compiled into the source code and if they are not properly documented can be difficult to understand what they do.
-
Instead of magic numbers use a real name that means something.
-
Use constants or enums to give meaning to the number.
const int WE_GOOFED = 19;
enum {
THEY_DIDNT_PAY= 16
};
4.2.8. Coding Style
4.2.8.1. Line Widths
-
A line should not exceed 78 characters. The Main argument to do this is because this allows us to easily print readable source code (yes some of us still do this). Also if you have a wide monitor you can fit multiple source files side by side!
4.2.8.2. Braces
-
All braces use the following format.
if (x == y) {
...
} else if (x > y) {
...
} else {
...
}
while (condition) {
...
}
for (;;) {
...
}
rtype functionName() {
...
}
-
Even for trivial if statements always use the brace syntax.
if (x == true) {
return;
}
This is clearer, less likely to cause future errors and has no effect on speed.
4.2.8.3. Indentation & Whitespace
-
Indentation is done by 4 spaces.
-
The content of a namespace is indented.
-
Don’t leave whitespace at the end of lines.
-
private:,public:, andprotected:are in line with the class definition. -
Code after
private:,public:,protected:andcase foo:is indented. -
Emacs people: Emacs may use a mixture of spaces and tabs to indent. Make sure this feature is disabled.
namespace FIFE {
class SomeClass {
public:
SomeClass();
virtual SomeClass();
protected:
int32_t m_someval;
};
} //FIFE
4.2.9. Includes
-
Try to use forward declarations rather to include other headers to reduce compiletime.
4.2.9.1. Platform specific includes
-
One of the issues with cross platform engine development are different include paths on different platforms. The FIFE team decided to introduce a set of helper include files to address this issue. You use these files instead of including the platform specific headers directly. Include these files after headers of the C++ std library but before any other 3rd party headers.
#include "video/opengl/fife_opengl.h" (1)
#include "audio/fife_openal.h" (2)
#include "util/base/fife_stdint.h" (3)
#include "util/math/fife_math.h (4)
| 1 | Instead of including any OpenGL headers directly |
| 2 | Instead of including any OpenAL headers directly |
| 3 | Instead of including the C99 stdint.h header directly |
| 4 | Instead of including the cmath header directly |
4.2.10. Multiple Inheritance
-
In case you feel tempted to use multiple inheritance, read this first: http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.4 (the whole article is a good read).
-
In most of the cases, you can avoid multiple inheritance altogether with proper design. If you still feel urge to use it, try to use pure interfaces (no method implementations in addition to empty destructor). Prefix these classes with 'I'-letter (e.g.
ITriggerController) -
If you still feel that implementation multi-inheritance is the way to go, discuss this first with other developers.
4.2.11. Friend declarations
In general, don’t use friend declarations. Friends tend to get overused, since at first sight they provide quick and easy solution for problem at hand. In many cases however, they violate encapsulation and decrease modularity. There are cases where friends might be beneficial, but consult other developers before making the decision.
4.2.12. Error Handling
-
Use exceptions when something exceptional has happened and cannot be recovered from. Prefer to make an entry in the FIFE log and somehow recover. See the [[Developer guidelines|developer-guidelines]] page for more info on exceptions.
-
Constructors should always throw an exception on error conditions.
-
Destructors should never throw an exception.
4.2.13. Sample Source Files
Template source files can be found from svn:
-
header: [sampleheader.h](https://github.com/fifengine/fifengine/blob/master/doc/templatefiles/sampleheader.h)
-
implementation: [samplecpp.cpp](https://github.com/fifengine/fifengine/blob/master/doc/templatefiles/samplecpp.cpp)
4.2.14. Commenting
The level of commenting outlined here may seem excessive, but it will make the code much easier to understand when a new coder has to work with the system, something that will inevitably be happening in an Open Source project like FIFE. So please, don’t become lax with the commenting.
4.2.14.1. Headers
-
Use doxygen-style comments in C++ headers: [Doxygen Manual](http://www.stack.nl/~dimitri/doxygen/manual.html)
4.2.14.2. Implementation
-
Try to write code someone else understands without any comment.
-
If you need to do something uncommon, or some special trick, comment.
-
Don’t comment on something obvious.
4.2.14.3. Commenting Methods
All methods must be documented, no matter how trivial. The method description preceeds its declaration in the header file and uses standard doxygen notation. For simple accessor functions and things of similar complexity comments along the lines of the following are acceptable.
/** Short function description**
*
* @param p1 Short desc
* @return Short description of return val
*/
rtype Function(ptype p1);
All methods' parameters and return types must be described. This is so that the doxygen generates documentation can be of real use. functions who’s use isn’t obvious require longer descriptions, which should include a more detailed description of its task as well as a sample of its use. Make the example as illustrative as possible.
/** Short function description
*
* Detailed description
* @code
* rtype rVal = complicatedFunction(param1, param2);
* @endcode
*
* @param p1 Description of parameter
* @param p2 Description of parameter
* @return Description of return value.
*/
rtype complicatedFunction(ptype1 p1, ptype2 p2);
Comments inside the body of a method should be kept to a minimum in simple functions again. But in large functions, especially those that encapsulate key algorithms, relatively detailed descriptions of how the code is opperating will make it much more maintainable. These should be kept to one of two line comments using the // syntax.
// converts from screen space to world space
x += xoffset;
y += yoffset;
// checks to see if an image is already loaded.
bool loaded;
loaded = image->getImageData() != 0;
4.2.14.4. Commenting Variables
Member variables should all be commented. This is not a substitute for good variable names, but rather a way to make clear the use of each member variable.
//! Window width in pixels.
int m_windowWidth;
//! Window height in pixels.
int m_windowHeight;
//! SDL_Surface which represents the renderable area of the screen.
SDL_Surface* m_screen;
Parameters are all commented in the method description comment block so additional comments are unnecessary.
Descriptions of local variables shouldn’t be necessary as long as descriptive names are used.
4.2.14.5. Commenting Enums
When relevant all enums should be fully commented (including values). This only applies if the value names are not self explanatory.
/** An enum type. **
* The documentation block cannot be put after the enum!
*/
enum EnumType {
int EVal1, /**< enum value 1 */
int EVal2 /**< enum value 2 */
};
4.2.14.6. Doxygen Tags
The following are not mandatory but it would be nice if everyone used them consistently.
| @see |
Use this to cross-reference another class/method/variable |
| @author |
If you are the original author or major contributor of a class/method you might as well take credit for it. Multiple author lines are supported! |
| @since |
If you are adding to the API you should mark which version of FIFE it will appear in first. |
| @deprecated |
Use this keyword if a function/class is now deprecated and marked for removal. |
| @throw |
When a method throws an exception you should document it using this keyword. |
| @pre |
This describes some pre-existing condition that the following code relies on. |
/** Pretty nice class.**
* This class is used to demonstrate a number of section commands.
*
* @author John Doe
* @author Jan Doe
* @since 0.3.4
* @deprecated Do not use in v0.3.5+. Replaced by EvenNicerClass.
* @see EvenNicerClass
* @pre First initialize the system.
* @bug Not all memory is freed when deleting an object of this class.
* @warning Improper use can crash your application
*/
class SomeNiceClass {};
4.2.15. Doxygen Tags: Gotchas
Along with other comments, use gotcha keywords to mark unfinished tasks in the code. Doxygen will parse your comments looking for these keywords, and making a report, so people can make a special effort where needed.
| @todo |
Means there’s more to do here, don’t forget. Can include known issues and bug or issue numbers if needed. |
| @bug |
This indicates that there is a known bug with the code. Be descriptive! Include bug or issue numbers! |
| @warning |
Use this when you need to bring special attention to whatever you are documenting. Perhaps there is a usage restriction or assumption that the user should know about! |
4.2.15.1. Including examples in your comments
For simple examples you can use @code and @endcode.
/** This is an awesome class.**
* It's made of pure awesomeness and should be used sparingly
* as to not waste the awesomeness.
*
* @code
* AwesomeClass ac;
* ac.doSomethingAwesome();
* @endcode
*/
4.2.16. License
-
If you directly copy and paste code from another project the original copyright header needs to stay in place! Don’t add a FIFE header to the file in this case.
-
If you used portions of code from other projects and integrated it into project files, add the FIFE header at the top of the file but add an additional remark after it that states the origin of the copied code parts.
-
You can use this example as a template in this case:
/***************************************************************************
* Copyright (C) 2005-2013 by the FIFE team *
* http://www.fifengine.net *
* This file is part of FIFE. *
* *
* FIFE is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
4.3. Python Coding Standards
We use a slightly modified version of the official [Style Guide for Python code](http://www.python.org/dev/peps/pep-0008/) as a basis for our coding standards. This article describes our modifications and additions and also contains a summary of the coding standards. Reading the official style guide is highly recommended before moving on, as this article merely complements it.
4.3.1. Files
-
Python files end with .py
-
Only one class per py file. (With a exception for classes that are extremely simple and clearly belong together.)
-
The files should be named after the (main)class they implement, but all in lowercase.
|
Executable python files
Python files which are meant to be executed directly, should have a shebang on the very first line. If your python file is not made for direct execution, it should not have neither a shebang. The shebang we use is: |
4.3.2. Naming Conventions
4.3.2.1. General
-
Internal or non-public variables, functions or classes are prefixed with an underscore
-
If you really do not want subclasses or other parts of python to use a member or method, prefix it with two underscores to invoke python’s name mangling
4.3.2.2. Package and module names
-
Module names are named after the class it contains, but all lowercase
-
Package names are also lowercase. Do not use underscores:
_
4.3.2.3. Class names
-
Class names use CamelCase. Example:
TestFactory, nottest_factory,testFactory,Test_Factory, etc.
4.3.2.4. Function and method names
This differ from python style guide
* Function names start with a small letter. (Example: def getRoofVisible())
4.3.2.5. Function and method arguments
-
Always use
selffor the first argument to instance methods. (Example:def setVisible(self, visible):) -
Always use
clsfor the first argument to class methods
TODO: Write an example
4.3.2.6. Variables and constants
-
Class members start with a prefix _ and are all lowercase (Example:
_roofshift_x) -
Parameter variables have no prefix and are also all lowercase. (Example:
myparamvar) -
Local variables have no prefix and are all lowercase. (Example:
mylocalvar) -
Constants are all uppercase with underscore separating the words. Example:
MAX_LINES
4.3.3. Coding Style
4.3.3.1. Indentation & Whitespace
-
Indentation is done by a real tab. This differs from python style guide!
-
Use 4 spaces per indentation level.
-
Never mix tabs and spaces!
-
Don’t leave whitespace at the end of lines.
-
Emacs people: Emacs may use a mixture of spaces and tabs to indent. Make sure this feature is disabled.
4.3.3.2. Blank lines
-
Separate top-level functions and class definitions with two blank lines.
-
Method definitions inside a class are separated by a single blank line.
-
Extra blank lines may be used (sparingly) to separate groups of related functions.
-
Use blank lines in functions, sparingly, to indicate logical sections.
4.3.3.3. Imports
-
Only one import per line
# Yes:
import os
import sys
# No:
import os, sys
-
Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants.
-
Imports should be grouped in the following order, separated by a blank line:
-
standard library imports
-
related third party imports
-
local application/library specific imports
-
-
Always use the absolute package path for all imports.
4.3.3.4. Functions
-
Keep your functions simple.
4.3.3.5. Arguments
Avoid using boolean parameters and if you need them, supply as keywords arguments. If you use them and you can supply the as positional arguments - don’t. The rationale here is that the meaning of boolean arguments is very difficult to see for the reader otherwise:
# Bad - What does the arg mean? Don't layout?
self.adaptLayout(False)
# Good - At least the reader has an idea what the arguments means.
self.adaptLayout(recurse=False)
4.3.3.6. Multiple Inheritance
-
In case you feel tempted to use multiple inheritance, read this first: http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.4 (even the whole article is a good read).
-
In most of the cases, you can avoid multiple inheritance altogether with proper design. If you still feel urge to use it, try to use pure interfaces (no method implementations in addition to empty destructor). Prefix these classes with
I-letter (e.g.ITriggerController) -
If you still feel that implementation multi-inheritance is the way to go, discuss this first with other developers.
4.3.4. Commenting
TODO: Add class documentation.
The level of commenting outlined here may seem excessive, but it will make the code much easier to understand when a new coder has to work with the system, something that will inevitably be happening in an Open Source project like FIFE. So please, don’t become lax with the commenting.
This is even more important as we only provide the engine. Remember each comment might fix a misunderstanding and thus problem for the game devs using FIFE.
Write the public documentation and comments from the point of a user.
4.3.4.1. Implementation
-
Try to write code someone else understands without any comment.
-
If you need to do something uncommon, or some special trick, comment.
-
Don’t comment on something obvious.
4.3.4.2. Commenting Files
All files should have a documentation string. That is the place to document the interaction and purpose of the module. You should link to most relevant classes and functions for the module. Try to explicitly state bugs, shortcomings and the dark and fuzzy areas of the code which need improvement.
"""
Foo Module
==========
...
Performance Issues
------------------
If you encounter performance issues with the Foo class. Remember
That the @L{FooSet.findSomething} method needs to iterate over all
foo instances. Do not use it in an inner loop. Instead use @L{getQueryDict}.
Good::
d = foo.getQueryDict()
for name in names:
for foo_instance in d.get(name,[]):
doSomething( foo_instance )
Bad::
for name in names:
for foo_instance in foo.findSomething(name):
doSomething( foo_instance )
"""
4.3.5. Commenting Methods
All methods should be documented, no matter how trivial. Here’s an example of how to document using epydoc style. If possible link to other relevant functions, provide a use case and give information on the expected results of the function.
def findSomething(self, param):
""" Find all instances of foo, which match param
Matching is performed by string comparison @C{foo.name == param}.
See @L{querySomething} for more complex queries.
Example::
fooList = stuff.findSomething("some")
for x in fooList:
print x.name # This will print 'some'
"""
Comments inside the body of a method should be kept to a minimum in simple functions again. But in large functions, especially those that encapsulate key algorithms, relatively detailed descriptions of how the code is operating will make it much more maintainable.
# converts from screen space to world space
x += xoffset
y += yoffset
# checks to see if an image is already loaded.
loaded = image.getImageData() is not None
4.3.6. Commenting Variables
Member variables should all be commented. Either individual variables, or blocks of variables with a similar function, as long as all member variables are in some way described. This is not a substitute for good variable names, but rather a way to make clear the use of each member variable.
The documentation should be in the init function.
def __init__(self):
# Initialise the window size with sane defaults.
self.window_width = self.DEFAULT_SIZE[0]
self.window_height = self.DEFAULT_SIZE[1]
# The command object handles all our commands.
# We proxy in the doXYZ() methods.
self.command = CommandObject(self)
Parameters are all commented in the method description comment block so additional comments are unnecessary.
Descriptions of local variables shouldn’t be necessary as long as descriptive names are used.
4.3.7. Gotchas
Along with other comments, use gotcha keywords to mark unfinished tasks in the code.
| TODO |
Means there’s more to do here, don’t forget. |
| FIXME |
Means there’s a known bug here, explain it and optionally give a trac id |
4.3.8. License
4.3.8.1. FIFE Python header
# -*- coding: utf-8 -*-
# ####################################################################
# Copyright (C) 2005-2013 by the FIFE team
# http://www.fifengine.net
# This file is part of FIFE.
#
# FIFE is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# ####################################################################
4.4. Coding Standard Checkers
The fifengine repository includes a ./build-tools folder with scripts for running
code quality checks. The tools listed below are also configured individually and
can be run standalone.
4.4.1. C++ Tools
4.4.1.1. clang-format
clang-format automatically formats C++
code according to the project style. Configuration is in .clang-format in the repository root.
Installation
# Linux
apt-get install clang-format
# Mac
brew install clang-format
# Windows - included with Visual Studio or LLVM
Usage
# Format a single file
clang-format -i engine/core/path/to/file.cpp
# Format all changed files
git diff --name-only | grep -E '\.(cpp|h)$' | xargs clang-format -i
# Check without modifying (CI mode)
clang-format --dry-run --Werror engine/core/path/to/file.cpp
4.4.1.2. clang-tidy
clang-tidy performs static analysis and
modernization checks beyond formatting. Configuration is in .clang-tidy in the
repository root.
Installation
# Linux
apt-get install clang-tidy
# Mac
brew install clang-tidy
Usage
# Analyze a file
clang-tidy engine/core/path/to/file.cpp -- -std=c++17
# Fix issues automatically where possible
clang-tidy --fix engine/core/path/to/file.cpp -- -std=c++17
4.4.1.3. cppcheck
cppcheck performs static analysis to find bugs, undefined behavior, and style issues.
Installation
# Linux
apt-get install cppcheck
# Mac
brew install cppcheck
Usage
# Check all engine source
cppcheck --enable=all --suppress=missingIncludeSystem engine/core/
# Check a single file
cppcheck engine/core/path/to/file.cpp
4.4.1.4. cpplint
cpplint checks Google C++ style compliance. Useful as a quick lint pass.
Installation
pip install cpplint
Usage
cpplint --recursive engine/core/
4.4.1.5. Astyle (legacy)
ArtisticStyle (astyle) was used historically for
formatting. It may still work but prefer clang-format for new work.
Configuration is in .astylerc.
Installation
apt-get install astyle
Usage
astyle --recursive --options=.astylerc "engine/core/*.h" "engine/core/*.cpp"
4.4.2. Python Tools
Python tooling is configured in pyproject.toml at the repository root.
4.4.2.1. Ruff
Ruff is a fast linter that replaces flake8, isort, and other linting tools.
Installation
pip install ruff
Usage
# Lint all Python files
ruff check engine/python/
# Fix auto-fixable issues
ruff check --fix engine/python/
4.4.2.2. Black
Black is an uncompromising code formatter.
Installation
pip install black
Usage
# Format all Python files
black engine/python/
# Check without modifying (CI mode)
black --check engine/python/
4.4.2.3. mypy
mypy performs static type checking for Python.
Installation
pip install mypy
Usage
# Type check all Python files
mypy engine/python/
# Check a single file
mypy engine/python/fife/module.py
4.4.3. Build Tools Scripts
The ./build-tools directory in the fifengine repository contains wrapper scripts
that run the above checkers. Consult that folder for the exact scripts available
and their usage. These scripts are typically used in CI and can also be run locally
before submitting pull requests.
5. Testing & Debugging
This chapter covers how to test and debug the FIFE engine itself.
5.1. Building and Running Tests
FIFE uses Catch2 for C++ unit tests and pytest for Python tests.
5.1.1. C++ Tests (Catch2)
To build and run C++ tests:
cd _build
cmake -DBUILD_TESTS=ON ..
cmake --build .
./tests/fife_tests
To run specific test cases:
./tests/fife_tests "[model]" # Run only model tests
./tests/fife_tests "[video]" # Run only video tests
./tests/fife_tests -s # Show successful tests
5.1.2. Python Tests
To run Python tests:
cd tests
python -m pytest
To run with verbose output:
python -m pytest -v
5.2. Writing New Unit Tests
5.2.1. C++ Test Structure
Create test files in tests/ following the Catch2 pattern:
#include <catch2/catch_test_macros.hpp>
#include "core/model/model.h"
TEST_CASE("Map creation", "[model]") {
fife::Model model;
fife::Map* map = model.createMap("test_map");
REQUIRE(map != nullptr);
REQUIRE(map->getId() == "test_map");
model.deleteMap(map);
}
5.2.2. Python Test Structure
Create test files in tests/ following the pytest pattern:
import fife
import pytest
def test_engine_init():
settings = fife.Settings()
engine = fife.Engine(settings)
engine.init()
assert engine.getModel() is not None
engine.destroy()
5.3. Debugging Setup
5.3.1. Visual Studio (Windows)
-
Open the CMake-generated
.slnfile in Visual Studio. -
Set the startup project to your test executable or demo.
-
Set breakpoints in C++ code.
-
Press F5 to start debugging.
For Python/C++ mixed debugging, use the Python Tools for Visual Studio (PTVS) extension.
5.3.2. VS Code (all platforms)
Install extensions: * C/C* for C debugging * *Python for Python debugging * CMake Tools for CMake integration
Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug FIFE Tests",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/_build/tests/fife_tests",
"args": [],
"cwd": "${workspaceFolder}",
"environment": []
}
]
}
5.3.3. CLion / KDevelop (Linux)
Open the repository root. CLion auto-detects CMake and provides integrated debugging. For KDevelop, import the CMake project and configure the run configuration.
5.3.4. Xcode (Mac)
Generate an Xcode project:
cmake -G Xcode ..
open fifengine.xcodeproj
Set breakpoints and use Xcode’s integrated debugger.
5.4. Common Debugging Scenarios
5.4.1. Breakpoints Across C++/Python Boundary
To debug C++ code called from Python:
-
Set breakpoints in the C++ code.
-
Run the Python script with the debugger attached.
-
When Python calls into C++ (via SWIG), the debugger will hit the breakpoint.
5.4.2. Memory Issues
-
Use Valgrind (Linux) to detect memory leaks:
valgrind --leak-check=full ./tests/fife_tests -
Use AddressSanitizer for faster detection:
cmake -DCMAKE_CXX_FLAGS="-fsanitize=address" ..
5.4.3. Rendering Pipeline Issues
-
Enable debug logging for the video module:
<Setting name="LogModules" type="str">video</Setting> <Setting name="LogLevelFilter" type="int">0</Setting> -
Use
RenderBackend::captureScreen()to save frame snapshots.
5.5. Profiling and Performance Analysis
5.5.1. Linux (perf)
perf record ./tests/fife_tests
perf report
5.5.2. macOS (Instruments)
Use Xcode Instruments for CPU, memory, and GPU profiling:
xcodebuild -scheme fife_tests -configuration Release
instruments -t "Time Profiler" ./build/Release/fife_tests
5.5.3. Windows (Visual Studio Profiler)
Use the Performance Profiler in Visual Studio (Debug → Performance Profiler).
5.6. Logging as a Debugging Tool
The logging system can be configured at runtime:
import fife
log = fife.LogManager.instance()
log.setLogLevelFilter(fife.LOG_LEVEL_DEBUG)
log.setModules("controller;video;model")
Log levels: LOG_DEBUG, LOG_LOG, LOG_WARN, LOG_ERROR, LOG_PANIC
6. Release Process
This chapter documents how FIFE releases are created and published.
6.1. Versioning Scheme
FIFE uses semantic versioning (semver): MAJOR.MINOR.PATCH
-
MAJOR — Incompatible API changes
-
MINOR — New functionality in a backwards-compatible manner
-
PATCH — Backwards-compatible bug fixes
Example: 0.5.0 → 0.5.1 (patch) → 0.6.0 (minor)
6.2. Release Checklist
Before creating a release:
-
[ ] All tests pass (C++ Catch2 tests, Python pytest tests)
-
[ ] Documentation is updated for new features
-
[ ] CHANGELOG.md is updated with release notes
-
[ ] Version number is bumped in CMakeLists.txt
-
[ ] Build succeeds on all platforms (Windows, Linux, macOS) via CI
-
[ ] No regressions in demos (rio_de_hola, pychan_demo)
6.3. CI/CD Pipeline
FIFE uses GitHub Actions for continuous integration.
6.3.1. GitHub Actions
The CI workflow runs on every push and pull request:
-
Builds C++ code on Linux (GCC, Clang)
-
Runs Catch2 unit tests
-
Runs Python tests
-
Builds documentation
Configuration: .github/workflows/ in the repository.
6.3.2. Appveyor
Appveyor builds Windows binaries:
-
Compiles with MSVC
-
Creates the Windows SDK installer
-
Publishes build artifacts
Configuration: appveyor.yml in the repository.
6.4. Creating a Release
-
Create a release branch from
master:git checkout -b release/0.6.0 master -
Update version in
CMakeLists.txt:set(FIFE_VERSION_MAJOR 0) set(FIFE_VERSION_MINOR 6) set(FIFE_VERSION_PATCH 0) -
Update
CHANGELOG.mdwith release notes. -
Commit and tag:
git add -A git commit -m "Release 0.6.0" git tag v0.6.0 git push origin v0.6.0 -
Create a GitHub Release from the tag with release notes.
-
CI builds artifacts automatically. Download and attach to the release.
6.5. Changelog Format
CHANGELOG.md follows this format:
# Changelog
## [0.6.0] - 2026-03-25
### Added
- New feature X
- New feature Y
### Changed
- Improved performance of Z
### Fixed
- Bug fix A
- Bug fix B
### Removed
- Deprecated feature C
Group changes by category: Added, Changed, Fixed, Removed.
7. Fife Windows SDK
| This chapter contains incomplete sections marked with TODO. |
The Fife Windows SDK is a collection of software development tools for working with Fifengine.
The Fife SDK installer build scripts fetch all required packages for working with fifengine, including build-tools and dependencies, prepares them for packaging and finally builds the "SDK" installer on Appveyor.
This chapter documents these build scripts and tasks, including fetching and extracting components and compiling the InnoSetup installers.
7.1. Repository Overview
Let’s start with an overview of the files and folders in the fife-windows-sdk repository:
├──build-scripts
│ ├── 1-download.bat
│ ├── 2-extract.bat
│ ├── 3-copy.bat
│ ├── 3-stripdown.bat
├──build-tools
│ ├── 7zip
│ ├── aria2
│ ├── innosetup
├──download-lists
│ ├── fifengine.txt
│ ├── fifengine-build-tools.txt
├──installer
│ ├── images
│ │ ├── fife.ico
│ │ ├── WizardImage.bmp
│ │ ├── WizardImage.xcf
│ │ ├── WizardSmallImage.bmp
│ │ ├── WizardSmallImage.xcf
│ ├── includes
│ ├── envpath.iss
├── appveyor.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
7.2. Appveyor
We are using Appveyor to continuously build and publish the installer.
The file appveyor.yml is Appveyor’s configuration file.
Important are the sections before_build, build_script, artifact, deploy.
7.3. Before Build Tasks (before_build)
Before we can build the installer, we need to download and extract the software components, which we later want to include in the installer. After the extraction, we copy and move some files and folders around. Then we delete several unnecessary files and folders in a stripdown run.
At the end of the before_build step, we have a proper folder structure
with all the components we want to ship, ready for inclusion into the installer.
7.3.1. 1-download
The 1-download.bat script downloads all required software components. It uses aria2 (a lightweight download utility) to fetch:
-
Pre-built FIFE dependencies (SDL2, SDL2_image, SDL2_ttf, SDL2_mixer, OpenAL, etc.)
-
Build tools (CMake, SWIG, Python)
-
FifeChan library
Downloads are fetched from: * GitHub releases and official project websites * Appveyor artifact storage (for pre-built dependencies)
The download list is defined in download-lists/fifengine.txt and download-lists/fifengine-build-tools.txt. Each line specifies a URL and target filename.
7.3.2. 2-extract
The 2-extract.bat script extracts downloaded archives using 7zip (7z.exe). It:
-
Extracts
.zip,.7z, and.tar.gzarchives -
Organizes extracted files into the expected directory structure
-
Renames versioned directories to consistent names (e.g.,
SDL2-2.28.0→SDL2)
7.3.3. 3-copy
The 3-copy.bat script copies files into the SDK staging directory:
-
Copies header files to
include/ -
Copies library files to
lib/ -
Copies DLLs to
bin/ -
Copies Python runtime and bindings
-
Copies CMake modules and build scripts
-
Copies documentation and examples
7.3.4. 4-stripdown
The 3-stripdown.bat script removes unnecessary files to reduce installer size:
-
Removes debug symbols and PDB files from Release builds
-
Removes source code files (
.cpp,.c) — only headers and libraries are shipped -
Removes unused platform-specific files (e.g., Linux
.sofiles on Windows) -
Removes documentation source files (only generated docs are included)
-
Strips redundant copies of shared libraries
7.4. Building the Installer (build_script)
The installer is build using the InnoSetup Compiler (iscc).
The property APP_VERSION is set from the APPVEYOR environment as %APPVEYOR_BUILD_VERSION%,
so that the installer is dynamically versionized from the outside.
build-tools\innosetup\iscc /DAPP_VERSION=%APPVEYOR_BUILD_VERSION% installer\fife-sdk.iss
The target location for installer is: fife-windows-sdk\_build.
The compiled setup executable has the following naming scheme: {#APP_NAME}-{#APP_VERSION}-Setup-{#APP_COMPILER}-x86,
for example: _build\FifeSDK-0.4.0-Setup-VC14-x86.exe"
7.4.1. Debugging the installer
-
You can create a log of the installation procedure by using the
/LOGCLI argument.FifeSDK-0.4.0-Setup-VC14-x86.exe /LOG=c:\fifesdk.log
7.5. Artifact Upload (artifact)
When the installer was successfully build, it is automatically published on Appveyor’s artifact storage.
7.6. Downloads (deploy)
When a new release version of the installer is tagged, then the installer is automatically published on Github Releases.
8. Image Atlas Creator
| This chapter is under development and contains incomplete sections. |
The Image Atlas Creator allows users to combine multiple images into an image atlas. This reduces the number of files you need to ship with your game and speeds up rendering!
The tool is written in C++ using Qt.
You find the repo here: https://github.com/fifengine/fifengine-atlas-creator
8.1. Usage
8.1.1. GUI Mode
Launch the application to open the graphical interface:
./atlas-creator
-
Click Add Images to select input images.
-
Configure atlas settings (max size, padding, output format).
-
Click Generate to create the atlas.
-
Preview the result and save.
8.1.2. Command-Line Mode
For batch processing, use the command-line interface:
./atlas-creator --input images/ --output atlas.png --format png --max-size 2048
Options:
| Option | Description |
|---|---|
|
Directory containing source images |
|
Output atlas image file |
|
Output format: png, tga, bmp |
|
Maximum atlas dimension (default: 4096) |
|
Padding between images in pixels (default: 1) |
|
Output metadata XML file (default: <output>.xml) |
8.1.3. Input
The supported Image File Types are: - png - jpg - jpeg - tga - bmp
See Source
Input images can be provided as: * A directory of images (processed recursively) * A list of individual files * A manifest file listing image paths
8.1.4. Output
The tool produces:
-
Atlas image — A single PNG/TGA/BMP containing all input images packed together.
-
Metadata XML — An XML file describing the position and size of each image within the atlas:
<atlas image="atlas.png"> <image name="hero_walk_0" x="0" y="0" width="32" height="32" /> <image name="hero_walk_1" x="32" y="0" width="32" height="32" /> </atlas>
This metadata file is compatible with FIFE’s object XML format and can be referenced directly in object definitions.
8.1.5. Common Use Cases
Create a sprite atlas from a directory of character sprites:
./atlas-creator --input sprites/hero/ --output hero_atlas.png --metadata hero_atlas.xml
Create a tile atlas with specific padding:
./atlas-creator --input tiles/ --output tileset.png --padding 2 --max-size 2048
Dependencies
Fifengine Dependencies
The following dependencies are needed to build FIFE from source:
-
Frameworks
-
Sound libraries
-
Graphics and GUI libraries
-
Python scripting-related libraries
-
Compression libraries
-
zlib >= 1.2
-
-
Serialization / XML libraries
-
Linux specific
FifeChan Dependencies
FifeChan is a C++ GUI library. It has several optional dependencies. The following dependencies are needed to build FifeChan from source:
-
SDL support
-
SDL2_mixer optional, for FPS demo
-
Optional SDL Contrib Dependencies (Set
ENABLE_SDL_CONTRIBtoONif you need them)
-
Font rendering
-
OpenGL (check drivers from your graphics card vendor)
-
Optional OpenGL Contrib Dependencies (Set
ENABLE_OPENGL_CONTRIBtoONif you need them)-
OpenGL-FreeType - optional
-
-
-
Testing optional, set
BUILD_TESTStoONto build tests-
catch2 - Unit testing framework
-
Checklist for new dependencies
In case a library gets outdated and has to be replaced or you want to introduce a completely new 3rd party library you should ensure it meets the following guidelines:
-
Cross-platform support (Linux, Windows, Mac)
-
Widely used by other projects and has an active community
-
Available to download as a package for most platforms
-
Has been in active development for a number of years
-
License is compatible with fife
Glossary
The glossary helps to ease communication between developers and users of fifengine by defining a set of commonly agreed upon terms.
- Agent
-
An agent is a dynamic map instance. It can move to different map locations at runtime.
- Animation
-
Sequence of image files that are played in succession to create illusion of e.g. walking. See http://en.wikipedia.org/wiki/Animations
- Archetype
-
Archetypes hold the basic data used in maps and throughout the game. They provide the IDs and names used in the Map Format.
- Atlas
-
Atlas or Image Atlas groups together several smaller images into a larger one for performance benefits.
- Backend
-
Backend From Wikipedia: "In software design, the front-end is the part of a software system that interacts directly with the user, and the back-end comprises the components that process the output from the front-end. The separation of software systems into "front ends" and "back ends" is a kind of abstraction that helps to keep different parts of the system separated."
- Camera
-
A viewport or scene. Multiple cameras can exist with different scenes being portrayed on each camera.
- Client
-
A game or tool that uses FIFE as it’s engine.
- Console
-
Console is an in game window that can be used to type commands for fife engine.
- Content
-
Media (images/music/sound fx/font/etc), map files, or GUI definition files.
- Contributor
-
Contributors are people working on FIFE on an occasional basis. Contributors have no write access to the FIFE Git repositories. Collaboration is done by forking a repository and sending patches back to the upstream repository via a Github pull request.
- Dataset
-
A collection of related content files (objects, maps, media) that form a complete or modular part of a game project.
- Developer
-
Developers are people working on FIFE on a regular basis. They have write access to the FIFE Git repositories.
- Elevation
-
Map consists of elevations. Elevation can be thought as a floor in case you think map being a building. Each map has to have at least one elevation.
- Event
-
An action or occurrence detected by the engine, such as mouse clicks, key presses, or timer ticks. Events are dispatched through the listener/callback system.
- FifeChan
-
FifeChan is a C GUI library (libfifechan). It's the successor of GuiChan. The pythonic binding to the C API is called PyChan.
- Game creator
-
A single person or a whole team of individuals who create a FIFE-based game.
- Gamma level
-
A display setting that controls the brightness curve of rendered output. Used to adjust visual appearance across different monitors.
- Geometry
-
The shape and structure defining how cells are arranged on a layer. FIFE supports square and hexagonal grid geometries.
- Gid
-
Graphical ID. Used to uniquely identify any piece of graphic inside a set of related xml-file fragments.
- Grid
-
A coordinate system that defines how cells are arranged on a layer. Grids determine adjacency, pathfinding connectivity, and cell dimensions.
- Layer
-
A grid of cells containing game instances. Layers organize game objects by type (e.g., ground, units, effects) and can have different properties like walkability and transparency.
- Location
-
A position in the game world specified by a layer and coordinates (either integer cell or floating-point exact position). Used for pathfinding and spatial queries.
- Map
-
World presentation from FIFE perspective. See Map model.
- Metamodel
-
The template/definition layer that describes object types, their properties, and visual representations before instances are placed in the game world.
- Model
-
The core data structure that represents the game world. Contains maps, which contain layers, which contain instances.
- Object
-
A template or archetype that defines properties (visual, behavior, metadata) shared by all instances created from it. Objects are defined in XML and loaded into the model.
- Offset
-
A displacement value applied to rendering position, often used to adjust where sprites or tiles appear relative to their logical cell coordinates.
- Palette
-
A limited color set used for indexed-color image formats. Allows efficient color replacement and recoloring of sprites.
- PyChan
-
PyChan is the pythonic binding to the C++ API of the GUI library FifeChan.
- Spritesheet animation
-
Specific type of atlas that represents only one action (animations for all defined directions). Typically, it’s one direction per row, one frame per column.
- Tid
-
Tile ID. Same as Gid, but used only for tile related graphics.
- Tile
-
A single cell graphic used for map rendering. Tiles are typically arranged in tilesets and referenced by their tile ID (Tid).
- Tileset
-
A collection of tile images organized for map rendering. Tilesets group related tiles and define their dimensions and properties.
- User
-
The term user is often utilized for expressing that the respective person is neither a developer nor a contributor of the development team.
- Visual
-
The visual representation data associated with an object, including images, animations, and rendering parameters like offset and transparency.
- View
-
The rendered perspective of the game world as seen through a camera. The view determines what portion of the map is visible and how it is projected onto the screen.