Home Wiki > openSUSE:Packaging Games
Sign up | Login

openSUSE:Packaging Games

tagline: From openSUSE


The page Packaging Games contains guidelines on how to package games for openSUSE and others using the openSUSE Build Service.

In addition to the standard packaging guidelines, there are a few other strong recommendations when packaging games.

Package separation

  • Package game files and data files separately, if possible, to reduce size of bugfix updates. This must be done if upstream packages game data in separate tarballs.
  • In most cases, game data packages (levels, artwork, sounds and music) should be BuildArch: noarch
  • Data files (maps, pixmaps, sounds) go in  %{_datadir}/%{name} , not %{_datadir}/games/%{name} . Binaries go in  %{_bindir} and not /usr/games. According to the FHS, the use of /usr/share/games and /usr/games is optional, and we recommend not using either for consistency, so that games are packaged like all other applications.
  • If you know that game with version 1.3.3 works with data of a version 1.2 or later, you could use the following scheme:

game.spec

Version:  1.3.3
Requires: game-data >= 1.2

game-data.spec

Version: 1.2
Requires: game >= 1.2

Commonly used libraries

  • For games that require SDL use SDL-devel (and possibly others like SDL_image-devel, SDL_mixer-devel, SDL_net-devel, etc.) in BuildRequires. Our SDL libraries provide these symbols and using libSDL-devel directly will not work on Fedora, Mandriva and older openSUSE releases.

Files and permissions

  • high score and runtime configuration files should go in /var/games/%{name} according to the FHS. If the package only puts a single file in this location, then it's acceptable to drop the %{name} subdirectory and place the file directly into /var/games.
  • man pages for games go in section 6: %{_mandir}/man6/ according to the FHS.
  • spec file group: Group: Amusements/Games
  • Desktop file category: Categories=Game; and any from this list as appropriate. See this mail for info on how todo this properly.
  • License file must be included to clarify legal status, even if upstream doesn't provide it in the source tarball.
  • Game service daemons, such as those provided by xpilot-ng-server and wesnoth, must run under their own userid, not 'root', 'games', or any other system user.
  • All %files must be owned by root,root, with the exception of certain shared files such as a scoreboard.
  • If necessary, a game can be made setgid 'games' in order to allow a shared scoreboard file. But only if necessary, and care should be taken to drop setgid privileges when not needed. The following example shows how to properly drop setuid/setgid privileges. A setgid bit requires prior approval by the SUSE security team though.
/* Keep a global pointer to the scoreboard file.  I know, global vars are
* ugly and should be avoided.  Your application might do this differently.
* This is just an example.
*/
extern FILE *scoreboard_filehandle;

/*
* Notice that we deal with dropping setgid immediately in main() after opening
* the scoreboard file, and before doing _anything_ else.  This minimizes the amount
* of code that is run setuid/setgid.
*/
int main(int argc, char **argv) {
gid_t realgid;
uid_t realuid;

/* Open the scoreboard file.  This could be NULL!  Users of this
* variable must check before using and not bother writing a
* scoreboard if it is null.
*
* The file is opened with mode "r+" to preserve the existing contents.
* This allows the program to first read the scoreboard and then write
* it out again with new values.  Just make sure you don't close() the file
* after reading it or you won't be able to write to it again.
*/
scoreboard_filehandle=fopen(SCOREBOARDFILE, "r+");

/* Figure out who we really are.
*/
realgid = getgid();
realuid = getuid();

/* This is where we drop our setuid/setgid privileges.
*/
if (setresgid(-1, realgid, realgid) != 0) {
perror("Could not drop setgid privileges.  Aborting.");
exit(1);
}
if (setresuid(-1, realuid, realuid) != 0) {
perror("Could not drop setuid privileges.  Aborting.");
exit(1);
}
/* ...Continue setting up the game... */

Games not designed for Linux/Unix

Some games are not designed for Linux/Unix : they run from a single directory, and try to write in it. A good solution for this is to create a bash wrapper which:

  1. creates a directory for the game in the user's home
  2. populates it with symlinks to the files in the game dir under /usr/share/%{name}
  3. cd into that dir and run the real binary

Such a script could look like this :

#!/bin/sh
GAME_LOCAL_DIR=$HOME/.mygame
GAME_DATA_DIR=/usr/share/mygame
GAME_EXECUTABLE=/usr/libexec/mygame/mygame
mkdir -p $GAME_LOCAL_DIR
cd $GAME_LOCAL_DIR
for dir in techs data maps tilesets; do
ln -snf $GAME_DATA_DIR/$dir $dir
done
test -d savegames || mkdir savegames
test -e mygame.ini || cp $GAME_DATA_DIR/mygame.ini mygame.ini
exec $GAME_EXECUTABLE "$@"

OpenGL Wrapper

If a game requires 3D accelerated graphic card you have to use DRI checking wrapper which will show an error dialog if DRI is not available explaining about Free Software and 3D drivers and then exit. What you must do is:

  1. Add: Requires: opengl-games-utils
  2. Add to %install:
     ln -s opengl-game-wrapper.sh $RPM_BUILD_ROOT%{_bindir}/%{name}-wrapper
  3. Add %{_bindir}/%{name}-wrapper to %files
  4. Change the .desktop file Exec entry from %{name} to %{name}-wrapper

This all assumes your main binary name == %{name}, otherwise adapt as necessary.

If you already have a wrapper script for one reason or the other, you can incorperate the checkDriOk function directly into your wrapper, no need todo a wrapper wrapper, see vegastrike's vegastrike-wrapper.sh file as example.