How to be a good upstream for games
Note: This is still under heavy discussion. You should not use this as a recommendation yet.
This is specific to games, for more general ways to become a good upstream, check out these pages:
If you store user data on a centralized service on your servers, you should ensure that this data is able to be backed up by users and by the community in general in the case that you decide to stop running the service. The data might be anything from high score lists to full online worlds. You should ensure that your data exports do not include private information such as passwords.
A centralized highscore is at least systemwide, so two different users will score on the same highscore list. Ideally, this list may also reside on a network, either locally or the Internet. Note that this means that it is impossible to prevent cheating.
How to implement a centralized highscore
If you want to implement a centralized highscore in your game, you should use the highscore library. At the moment of this writing, it doesn't exist yet. Its proposed interface is described below. If your game already has a server-wide highscore system, it is a good idea to change it to use the library instead. However, it doesn't have to be a priority. Below, a method is described which you can use to make your game more secure. If you don't have the time (yet) to start using the library, please implement this instead.
Interface of the library:
A highscore consists of an integer score plus any number of fields with arbitrary strings in it. The integer is used for sorting; it should not be displayed, so it should be repeated as a text string unless it should not be shown.
Library interface (seen from the game):
- Get the current list of highscores.
- Get an fd which should be selected for read to see if a new highscore event occurs.
- Free the list. (Happens in destructor for languages which support them.)
- Send a new score, which is potentially a highscore. Returns: position in the high score list. This is the 0-based position, or ~0 if it is not a new highscore. To be notified of changes, the game should make its main loop check for read on the given fd. When the fd can be read, the current list should be retrieved again.
Method for securing centralized highscore systems
When implementing a centralized highscore system, most games would use the setgid bit on their executable, to be able to write to a central highscore file. This is a security issue. This is avoided when using the highscore shared library. If it is not feasable to use that, you should minimize the risk that this produces. This can be done like this:
- At the start of the game, open the highscore file.
- Immediately after that, drop the setgid priviledges.
- Never close the file, only truncate and rewrite it. The last part is most of the work. For a code snippet implementing the first part, you can use http://fedoraproject.org/wiki/SIGs/Games/Packaging.
Do not call home or send highscores or other data to the network without permission from the user.
Do not use proprietary or custom formats, especially within the source package everything should be modifiable with standard tools. If you must use custom formats at runtime, please make sure to create those files at build time from normal file formats stored in your version control system. It is really helpful if you use standard tools instead of inventing custom pack formats, especially if formats like ZIP and tar are functional equivalents. If you need custom formats, please place the software used for generating them under free licenses.
The Debian Free Software Guidelines require "source code" also known as the preferred form for modification, for both programs and non-program software such as documentation, artwork and other data assets. Other distributions have similar policies. When in doubt, you should ensure that users have the exact same materials as those who develop the games. It is quite rare for the game development community to think about it significantly. Some guidelines:
Don't put generated files in your version control repository. Don't manually modify generated files after they are generated. If your build processes for your built data files take a long time and you want to save people time, simply create a second release tarball for pre-built data. Make sure everything can be rendered/built with DFSG-free tools and that one of the make targets clean/distclean/maintainer-clean removes any generated files, so that Debian can ensure that the building/rendering still works.
Render text at build time or preferably at runtime (enables i18n). Use the system fonts. If you choose a specific font then use fontconfig to find it rather than bundling it with your project. If you create your own special font, please distribute it in source form (for exampletext format) and ensure that it can be built using free tools. When you enable i18n your chosen font probably won't have all the required characters so your text rendering system should be prepared to fall back on other fonts on the system.
Pre-rendered images of layered raster images are not source. Instead include the multi-layer raster images (Gimp/Photoshop/etc).
Pre-rendered images of vector image files are not source. Instead include the SVG or similar and render the images at build time or runtime.
Pre-rendered images of 3D models are not source. Instead include the models, textures etc and render the images at build time or runtime.
Pre-encoded compressed video files are not source. Instead include the models, textures etc and render them at build time or runtime.
Pre-encoded compressed audio files are not source. Instead include the tracker projects, the csound programs or whatever you used to generate the audio. Please ensure that it is possible to automatically generate the in-game audio using DFSG-free tools. With audio, try to keep original recordings (or MIDI input or other recorded input) around and apply any effects at build time to a copy so that the effects are easily tweakable or the recording easily replaceable with the same effects applied.
Pre-generated binary level files are not source. They should be generated at build time. See also thesection.
Pre-generated C/C++ code created from bison/yacc/flex lexers and parsers is not source. The C/C++ code should be generated at build time.
If you have a large amount of data (say 50MB), please split your project into multiple source tarballs for code and data. If you have a really really large amount of data (say 500MB) it may be helpful to split your data tarball into multiple tarballs based on the kind of data (models, textures, audio) or some other criteria (level hardness, load order etc).
If your game has a full-screen mode, it is important to implement this properly. Especially if the full-screen mode uses a different resolution than that of the desktop, you can potentially disrupt other applications or the user's desktop experience. Make sure you always have a quick way to go back to windowed mode, and ensure the old desktop resolution is restored properly if the game exits (also try to make this happen in case the game exits abnormally).
It is recommended that the first time a game starts, it starts in windowed mode. Subsequent times the game should use the mode the user selected the previous time.
Almost all window managers allow a window to be made full-screen. If possible, respect the window manager events and allow this to manage the full-screen state of your game. However, this only works well if you don't have to change the screen resolution, and do not capture all keyboard events. If your game does need to change resolution and/or captures all keyboard events, make sure there is a hotkey to quickly change to/from full-screen mode. The hotkey should work in all situations. The full-screen hotkey, in order of preference, is:
- Window manager default
- F11 and/or Alt-F11 (since this is the default for most window managers)
- Alt-Enter (is used in various games)
- Alt-F, Ctrl-F, Command-F and/or F (is used in various games) Of course, the hotkey should not interfere with gameplay. You can also respond to more than one hotkey.
If your game can run in full-screen, ideally it should use the native resolution of the display. However, sometimes this is not desirable. The list of possible resolutions can be very long, especially for large displays. However, integer divisions of the native resolution are usually best, as they do not introduce aliasing artifacts when the graphics card or the display itself scales them up to the native resolution. For example, the integer divisions of a 1920×1080 screen are 960×540, 640×360, 480×270, and so on. Try to keep the aspect ratio of the native resolution, otherwise the image might be stretched out horizontally or vertically.
If your game is made for a single, fixed resolution, then it might help to implement your own scalers, either by just duplicating pixels, or a suitable OpenGL shader, or an algorithm such as hqx, scale2x or advanced depixelisation. This usually produces better results than the naive linear interpolation that most graphics cards and displays implement.
Your game probably comes with some documentation. If you do not have an in-game documentation browser, it can still be helpful to add a "help" option/button/hotkey, that launches a suitable documentation viewer. You should ensure you have left full-screen mode and do not grab the keyboard and mouse anymore before launching the viewer. You can use the
xdg-open command to launch a viewer appropriate for the format of the documentation.
Links to other pages about upstream on this wiki: