Game Engine Design Document

I. Introduction

This document describes the architecture of a game engine. (The game has not yet been given a working name.)

More specifically, this document describes the engine in its initial state, prior to a session of game play. This is because the game is one in which modification of the engine's source code by the players is the central play mechanic.

Since any specific detail of the engine can change during the course of a game session, references to its features or limitations will necessarily refer to the engine in its initial state, before any modification. Therefore, it should be taken as implicit that none of the constraints or requirements outlined in this document should be interpreted as necessarily applying to the engine once game play commences. (Occasionally, aspects will be called out as being generally desirable throughout game play, but solely to highlight that the engine's initial design should encourage their preservation.)

II. Nouns

Player — a participant in a session of game play. "Player" can refer to both the game entity that is competing in the session, and to the human being in control of the entity. Players are the only entities that can participate in game play activities such as submitting proposals and voting.

Session — a period of game play. A session begins with the game engine in its initial state, and ends with a winning condition having been achieved (or when all of the players quit the game).

Proposal — A change to the game engine, submitted by a player during a session. A proposal must pass its voting period in order to be applied.

Game State — The program and all of its variables that affect game play at a specific point in time.

III. Design Goals

The architecture of the game engine has three central goals: simplicity, modifiability, and self-sufficiency.

The first two goals will occasionally be at odds with each other. In such situations, all else being equal, modifiability should probably be given slightly higher priority. Ultimately, the more confident players can be when introducing sweeping changes to the engine, the more options they will have during the course of game play.

IV. Overview

The game engine consists of the following major components: the API, the Work Queue, the State Manager, the Code Editor, and the Game Logic. These components are described below in further detail.

IV.1. API

The game engine will provide a single port for communication with game clients. The details of the interface are TBD. An HTTP port using JSON in a REST interface is an obvious choice; another one would be to accept text messages formatted as per email, with a special prefix to indicate lines that contain API calls. The Erlang programming language may tip the decision in a different direction.

The API will provide calls for initiating all player actions, as well as calls for generally querying aspects of the game state. Ideally the API will be designed flexibly enough that as changes introduce new aspects of the game state, the existing APIs will naturally expand to include them. (This also means that the APIs should behave consistently when queried about nonexistent or no-longer-existent aspects of the game state.)

IV.2. Work Queue

The work queue will be a FIFO list of tasks. Any and all game state changes should be accomplished by submitting a task to the work queue. This ensures that all changes to the game state are applied sequentially and in a predictable fashion.

A task on the work queue will typically make changes to the game state. If any such changes cause further changes as a result, those changes would be applied as well. Sometimes game state changes will also cause new tasks to be added to the work queue. As a general rule of thumb, it is preferable for all direct consequences of a state change to be applied in the course of a single task, while indirect consequences will be handled in a new task.

(For example, a task may have the job of applying a successful proposal. A side effect of this may be that the proposal's author is awarded points, and this would probably be done inside the same task. Score change may trigger other game effects; these effects may not have anything to do with proposals, and might have further consequences of their own. Therefore, these would probably be handled in a separate task, which the point-awarding code would append to the work queue automatically.)

IV.3. State Manager

The game's state includes most all information about the running program, including not only the set of all game entities (such as players) and all of their mutable attributes, but also the engine's current code, and such software objects as the tasks in the work queue.

It is the job of the state manager to provide functions to change the state (upon validation, and to reject state changes that do not pass validation), and to transparently mirror the data in the file system. If the game engine crashses, it should be able to be restarted without any noticeable loss of game state.

The state manager will need to be flexible and permissive about handling incongruities in the game state, such as dealing with the presence of entities that the engine does not (any longer) recognize.

IV.4. Code Editor

The process of applying changes to the source code could be a very tricky process, and so it will probably need its own module for running this process.

(The exact form that change specifications will take is TBD. Ideally they would look like traditional diffs, and the Unix patch utility would be used to apply them. This would allow players to submit fine-grained code change proposals, with some basic safeguards against collisions. If a proposal is modified in between the time that a player submits a proposal and the voting period ends, it makes it harder for players to avoid problems and failures outside of their control. The downside is that using patch directly would violate the goal of self-sufficiency, while reimplementing patch's functionality inside the game engine would almost certainly violate simplicity.)

Any indication that a code change is not doing what was expected (e.g. it attempts to replace a function that doesn't currently exist) should cause the code change to abort. In addition, the editor should also do some basic validation. Code that contains syntax errors (or similar surface-level problems) should also trigger an abort.

If any part of a proposed change causes an abort, then the whole change should be discarded: accepting partial changes is too likely to be disastrous. The code to do this is probably not going to be trivial.

Regardless of safeguards, there will always be situations where a fatal bug can be introduced without detection. Presumably if a crticial of code is no longer working, that entire functionality will become unavailable until such time as it is fixed. It's not clear how a game could recover if this module was the one that was disabled. Presumably players should be extremely cautious about proceeding with changes to the editor module. On the other hand, it is a central aspect of the game's appeal that all parts of the game engine are susceptible to modifcation.

This is the one place in the design where I feel certain that one of the three goals will have to be sacrificed. The question is which one.

IV.5. Game Logic

This section of the game engine will be where the "rules" of the game are embodied and enacted. All of the if-this-then-that logic will take place in this module.

This will presumably be where the majority of changes are made to the code, hopefully permitting the other three sections to be as straightforward and robust as possible.

V. The Environment of the Program

The game engine will be self-contained to the degree that this is reasonably possible. However, no program runs in a complete vacuum, and there needs to be some assumptions about the platform on which the game engine runs.

Finally, there is one rule of game play that must necessarily stand outside of the game engine:

The rationale behind this meta-rule is to encourage players to scrutinize proposals carefully, and be suspicious of changes that look buggy. Players can choose to play without this rule, however, so long as everyone explicitly agrees to such a modification before game play begins.

VI. Game Play Activities

This section describes the main activities that the game logic will provide.

VI.1. Player Participation

The list of pariticipating players must be determined before the game can commence. When the list of players is communicated to the game engine, the game session begins.

(The method whereby the list is communicated is TBD. Some possible options: the list is sent to an API, before which all other API calls are ignored; the list is stored in a file read by the game engine during initialization; the list is provided on the command-line when the engine is first run.)

Players may not be added to the game after a session has begun. However, players are free to remove themselves in mid-game. Removal is permanent: players who forfeit in this manner cannot later rejoin the game. When a player forfeits, any and all of their outstanding votes are deleted.

VI.2. Submitting Proposals

A proposal consists of a title, a set of changes to the code and/or game state, and optionally some descriptive text. A player can use the descriptive text to e.g. argue the merits of their proposal, but it has no other specific purpose.

When a proposal has been submitted, it is assigned a unique identifier, and its voting period begins. A proposal's voting period continues until such time as all players have voted on the proposal (see below), or until the maximum time of 24 hours is reached.

When a proposal's voting period ends, the proposal will either be adopted or retired. If it is adopted, the changes it contains will be applied to the game engine's code and/or the state. If it is retired, it is removed from consideration with no futher effect on the game state.

There can be more than one proposal with an active voting period at any given time.

VI.3. Voting

During a proposal's voting period, players may vote YES, NO, or ABSTAIN on that proposal. Each player can submit one vote per proposal. If a player votes more than once on a proposal, only their last vote will be retained. If a proposal's voting period comes to an end before every player has voted, the remaining players will be counted as having cast an ABSTAIN vote.

Voting is done publicly; everyone can see how everyone else voted during and after a proposal's voting session.

VI.4. Applying Changes

For a proposal to be adopted, it must receive a majority of YES votes, not including ABSTAIN votes in the count. A proposal that receives an equal or smaller number of YES votes than of NO votes will be retired.

In addition, if more than one-third of a proposal's votes are ABSTAIN votes, then the proposal will be considered to have failed quorum, and will be retired regardless of the other votes.

When a proposal is adopted, the changes it describes are applied to the current source code of the game engine. Any affected code is reloaded and game play continues.

If one or more changes cannot be applied as described, or if the altered code is identified as being invalid (e.g. containing syntax errors or the like), then all of the proposal's changes are discarded: any partial changes that have already been applied will be undone.

VI.5. Awarding Points

All players begin the game session with zero points.

Whenever a proposed change is successfully adopted, the player who created the original proposal is awarded 10 points.

VI.6. Winning Condition

If at any time a player achieves a winning condition, the game session immediately comes to an end. No further change to the game state can take place, and any tasks still on the work queue are ignored.

If at any time a player has 500 points, they are declared the winner.

VII. Miscellaneous

The (relatively) arbitrary constants of the game logic should all be declared in one place, so that players will be encouraged to propose modifications to their values.

In the initial state, these constants would include: