The Manifest
Each game built for Gamewall needs to specify a certain amount of metadata about itself, to allow both the users and the engine itself to handle it correctly. The manifest is a collection of these pieces of data, validated against a spec both when a game is loaded into the sandbox, and when it is uploaded into the Gamewall service.
ℹ️Note ℹ️
Throughout the documentation, we will specify examples for a simple demo of a simple bouncy ball demo. You can download a development build of the completed demo here (TODO: create the demo, upload it, and paste the link here)
The manifest is a human-readable YAML file, with properties which can be broken down into:
The Manifest Version
Example:
gameWallSpec: '1.0'
The manifest version specifies the format of all other elements of the manifest. It MUST be a string, and for compatibility with this documentation, it MUST be equal to '1.0'
. Currently, this is the only accepted value. Later on, other manifest versions might be created, but this documentation is for manifest version 1.0
.
Game Identity Metadata
Example:
name: My Game # human-readable name
codename: my-game # machine name (limited to a-z, 0-9, and -)
description: | # a short description that shows up for your game entry
An example game to show the Gamewall SDK
thumbnail: thumbnail.png # an image for your game entry, in ./assets
author: Me Incorporated # human-readable author name
version: '0.1.0' # game version, must follow semver
This section contains information about the identity of the game: its name, preferred filename, descriptive data, and version number.
This consists of the following fields:
name
: A human-readable name. This is what the system will call the game, exposed to both the screen operator partners, and the end users.codename
: A machine-readable name, consisting of only lowercase letters, numbers, and dashes. It also cannot start or end with a dash, or consist of a single letter. This is a unique name by which the system refers to the game. It also determines default filenames.description
: A short description, at most 2048 characters, markdown-enabled. This is an explanation of the game shown to screen operators.thumbnail
: A 16x9 thumbnail image shown to both screen operators and end users.author
: A human-readable name of the developer entity of the game.version
: A version number, MUST be a string and follow semantic versioning. This may be used internally to manage game versions.
ℹ️Note ℹ️
Semver includes provisions about backwards compatibility. In the case of Gamewall, this compatibility concerns the configurables (see below), if you introduce breaking changes that would make a previous game config incompatible with your new game package, you must bump the major version. Minor version bumps are expected when you add new configuration options in a backwards compatible way. However, version bumps are not restricted to these changes.
Screen and Player Configuration
This section of the manifest deals with the available screens the game is able to display and available player configuration. Operators can configure the screens they wish to use out of the presented list, and further restrict player counts, if they deem necessary.
Example:
screensAvailable: # an array of screens your game can show
- screen
- controller
defaults: # specifies which screens to show unless otherwise specified
screen: screen # the default choice for large-format screens
controller: controller # the default choice for user devices
playerCount: # specifies how many players your game is able to support
min: 1
max: 4
The
screensAvailable
field is required to be an array of arbitrary string identifiers for available screens, using any ofa-zA-Z0-9_-
but not starting or ending in either an underscore or a dash. It is up to the game's code to handle the screens offered, as discussed in the chapters about rendering and setup.The
defaults
field is required and it must have exactly the two fields depicted above:screen
andcontroller
. Both fields must correspond to one of the available screens. These will be used as the default configuration of the game. Operators may reconfigure each screen the game is presented on, and reconfigure controllers on a per-room basis.The
playerCount
field is required and has to either- have a
min
and amax
field, both of which positive integers, or - have an
exact
field, a positive integer
This controls the number of players who can play the game controlled by the manifest. The Gamewall Engine guarantees that the player count will stay within these bounds, and operators can only apply additional restrictions.
- have a
Game Loop Settings
This section deals with the small part of the technical setup of the game which the execution environment, including the server, has to be aware of. The server will not execute the game sandbox, it only reads the manifest, therefore all information it needs to run the game must be available here.
Example:
settings:
tickRate: 128
queueLength: 80
autoInputDelay: true
This section only consists of one field, settings
, an object with two required parameters:
tickRate
: the number of ticks per second. This can be thought of as a Hz measurement at which the game loop operates (although real-world logic is slightly fuzzier because of the backtrack mechanism). This must be known in advance and synchronized between all participants.queueLength
: the number of ticks kept "alive" by the game at any given moment. Delayed inputs can only be received up to this limit, after this the game state is frozen and considered final. Synchronizations also communicate game state delayed byqueueLength
amount of ticks, which the receiving party rebuilds at the time of a sync to recreate the entire currently active queue.
There are a number of optional execution parameters as well:
inputDelay
: a number of milliseconds to artificially delay all user inputs. (Inputs will still be sent out immediately but point to ticks occurring in the future.) This allows the inputs some time to traverse the network without inducing delayed inputs and jumpy behavior in the game.autoInputDelay
: boolean, specifies whether the engine should control the input delay or if it should be fixed instead. Deferring control to the engine allows for automatic adjustment to network conditions, in exchange for slightly less predictable latency behavior. Whether or not this option makes sense depends on the game. We recommend using this by default and opting out if necessary.
Configurables
This section defines a list of game-specific parameters for operators to configure. Each entry in the "configurables" array represents a configurable field with the following properties:
id
- Type:
string
- Description: A unique identifier for the field. This identifier is used to refer to the field within the system.
- Example:
"some"
type
- Type:
string
- Description: The data type of the configurable field.
- Accepted Values:
Type | Description | Example |
---|---|---|
string | Represents a simple textual type. | "Default String" |
number | Represents a numerical value. | 0 |
list | A list type that can contain multiple elements. | ["example", "string"] |
select | Allows selection of one value from a predefined set. | "RED" |
multiselect | Allows selection of multiple values from a predefined set. | ["TAG1", "TAG2"] |
object | A complex type for grouping other fields. | { "field1": "value1", "field2": "value2" } |
color | Represents a color code (e.g., hexadecimal format). | "#FFFFFF" |
file | A field containing the file path relative to an asset folder. | "path/to/img.png" |
boolean | A true/false value. | true |
- Example:
"string"
- Advanced Configurable Field Types
list
:items
: Describes the individual list elements.jsx{ "id": "stringList", "type": "list", "items": { "type": "string", "rules": { "min": 1, "nullable": false } }, "default": ["item1", "item2"] }
select
andmultiselect
:values
: Defines the possible scalar values.jsx{ "id": "colorChoice", "type": "select", "values": ["red", "green", "blue"], "default": "red" }
object
:fields
: Nested field definitions that describe the structure of the object.jsx{ "id": "userProfile", "type": "object", "fields": [ { "id": "firstName", "type": "string", "rules": { "required": true } }, { "id": "age", "type": "number", "rules": { "min": 0 } } ], "default": { "firstName": "Alice", "age": 34 } }
rules
(Optional)
- Type:
object
- Description: Defines the validation rules or constraints applicable to the field value.
- Common Rules:
required
: Indicates if the field is mandatory (boolean). Default:false
min
,max
: Numerical limits fornumber
types.minLength
,maxLength
: Limits forstring
andlist
types.nullable
: Determines if the field can be null (boolean). Default:false
default
(Optional)
- Type: Matches the
type
of the field - Description: The default value that the field will assume if not explicitly set.
localized
(Optional)
- Type:
boolean
- Description: Indicates if the field supports localization for its values.
{
"id": "gameTitle",
"type": "string",
"localized": true,
"default": {
"en": "Wheel of Fortune",
"hu": "Szerencsekerék",
"es": "Ruleta de la Fortuna"
},
"localization": {
"en": {
"name": "Game Title",
"description": "The title of the game."
},
"hu": {
"name": "Játék Cím",
"description": "A játék címe."
},
"es": {
"name": "Título del Juego",
"description": "El título del juego."
}
}
}
localization
(Optional)
Type:
object
Description: Provides localized names and descriptions for different languages. This is particularly useful for improving the usability and accessibility of admin interfaces.
Allow localization of each value within
select
andmultiselect
fields.Impact on Admin Interface: Localization information allows fields to be displayed with descriptive names and details. Without it, fields are identified only by their
id
, making the interface less intuitive.Structure Example:
json{ "en": { "name": "Field Name", "description": "Description of the field.", "values": { "value1": { "name": "Value 1", "description": "Description for value 1." }, "value2": { "name": "Value 2", "description": "Description for value 2." } } }, "es": { "name": "Nombre del Campo", "description": "Descripción del campo.", "values": { "value1": { "name": "Valor 1", "description": "Descripción para el valor 1." }, "value2": { "name": "Valor 2", "description": "Descripción para el valor 2." } } } }