Skip to content

The Game API

SmartFoxServer 3 provides a set of client and server API specifically designed for game creation and management, including public and private games, game invitations, User and Room matching and more. The Game API is based on three fundamental building blocks:

  • Match Expressions: allow to assemble complex search criteria to perform filters and queries on Rooms and Users
  • Invitations: a generic Invitation system that helps managing multiple invitations to private games, but can be also used in other activities involving invitations
  • SFSGame class: a type of Room specifically designed for managing games and providing unique services for advanced game management

These three components are highly versatile and can be used singularly, for a specific task, or composed together to create advanced server behaviors, as you will learn in the following sections.

Overview

Accessing the API

SmartFoxServer 3 provides easy access to its API using specialized entry points for each API category. When developing a server side Extension you have access to the following API via these convenience methods:

  • getSFSApi(): returns a reference to the main SFS API
  • getBuddyApi(): returns a reference to the Buddy List API
  • getGameApi(): returns a reference to the Game API
  • getMMOApi(): returns a reference to the MMO API

Match Expressions

Match Expressions are built similar to "if" statements in most programming languages. Here's a server-side example to get started:

var exp = new MatchExpression('rank', NumberMatch.GREATER_THAN, 5).
        and('country', StringMatch.EQUALS, 'Italy');

On client side you will find a very similar syntax as well. Expressions are made of three elements:

  • Variable name
  • Match operator
  • Value

Additionally any number of expressions can be linked together with a logical AND / OR operator, just like in regular code. In the above example we have created an expression that will check for a rank value > 5 and a country value == "Italy".

But... where is this set of conditions applied to? Normally expressions are used to match Users (via their User Variables) and Rooms (via their Room Variables). The standard SFS API provides two useful methods called findUsers() and findRooms() where you can execute any Match Expression and obtain the filtered set of Users/Rooms.

A small example will clarify this better:

List<User> matchingUsers = sfsApi.findUsers(zone.getUserList(), exp, 50);

The first argument provides a list of User objects where to search, in this case all Users inside the current Zone. The second argument is the Match Expression we just created at the beginning of this section, and the last number (50) is an optional limit for the amount of returned elements. In this case we want to search for no more than 50 matching elements (passing 0 as the limit would return all Users that match).

The search options are not just limited to User/Room Variables name. In fact the Matching engine provides two extra classes, RoomProperties and UserProperties, where you can access many specific attributes of the Room and User classes.

This is an example of matching specific Room properties and Variables:

// Prepare match expression
var exp = new MatchExpression(RoomProperties.IS_GAME, BoolMatch.EQUALS, true)
                        .and(RoomProperties.HAS_FREE_PLAYER_SLOTS, BoolMatch.EQUALS, true)
                        .and("isGameStarted", BoolMatch.EQUALS, false);

// Search Rooms
var joinableRooms = sfsApi.findRooms(zone.getRoomListFromGroup("chess"), exp, 0);

Here we're matching all game Rooms that have at least one free player slot and where the isStarted variable is set to false. Additionally the search will be performed only in the Room Group called chess.

Advanced features

The Match Expressions offer advanced capabilities for searching through nested data structures such as SFSObject and SFSArray. This is done via a simple dot-syntax expressions. Here's an example of how it works:

var exp = new MatchExpression("europe.italy.capital", StringMatch.EQUALS, "Rome");

The above example goes deep down into an SFSObject called europe, taking the italy object (another SFSObject) and finally reading its String field capital and matching it with another String. Here is one more examples using SFSObject and SFSArray:

var exp = new MatchExpression("europe.italy.majorCities.3.name", StringMatch.EQUALS, "Milan");

From the italy object we obtain a majorCities SFSArray and we grab the third item in it (the .3 expression means 'give me the element at index == 3'). The item is again an SFSObject whose name property we finally compare to a String.

You can also run multiple matching passes if you need complex searches to be performed. For instance you can run a first match and obtain a list of filtered Rooms and then use it to apply another expression to further refine your search, and so on and so forth. Also you will learn more interesting usages of Match Expressions in conjunction with the SFSGame class later in this article.

For more details on Match Expression we recommend to consult the javadoc, under the com.smartfoxserver.entities.match package.

Invitations

The invitation system included in SmartFoxServer 3 provides a generic framework for sending invitations to one ore more connected users and easily manage their responses, including their expired ones. Invitations can be used to challenge players in a game, invite buddies to the user's place, ask permissions for specific tasks such as participating in a multi-user call, etc.

Creating an invitation is very simple; we just need four parameters:

  • Inviter: the User starting the invitation
  • Invitee: the invited User/Player/Buddy
  • Expiry time: the amount of seconds allowed for the invitee to reply
  • Custom parameters: an SFSObject with specific invitation data (a message, a picture, game details, etc)

The invited User will receive the invitation and will be able to reply within the specified amount of time. A simple ACCEPT or REFUSE code is all it takes to reply, plus an optional SFSObject with response parameters, if needed. In case no response is sent to the server within the expected time, the invitation will be considered refused.

public class GameInvitation extends SFSExtension
{
    @Override
    public void init() 
    {
        // Init code here 
    }

    public void sendInvitation()
    {
        // Prepare Invitation object
        User inviter = getParentZone().getUserByName("Kermit");
        User invitee = getParentZone().getUserByName("Piggy");

        // We set the timeout for a reply to 50 seconds 
        Invitation invitation = new SFSInvitation(inviter, invitee, 50);

        // Send the invitation 
        getGameAPI().sendInvitation(invitation, new InvitationCallback()
        {
            @Override
            public void onRefused(Invitation invObj, ISFSObject params)
            {
                // Handle the refused invitation...
            }

            @Override
            public void onExpired(Invitation invObj)
            {
                // Handle the expired invitation...
            }

            @Override
            public void onAccepted(Invitation invObj, ISFSObject params)
            {
                // Handle the accepted invitation...
            }
        });
    }
}

For more details about Invitations check the javadoc, specifically the SFSGameAPI class and the com.smartfoxserver.entities.invitation package. Additional information is also available in the client side API documentation

SFSGame

The SFSGame class extends the normal capabilities of a Room, adding the ability to set the game as public or private and providing a list of invited people that the system will invite in the game. Additionally the system is able to invite more Users if the number of players is not sufficient to start the game.

Each game can be configured to match specific types of Users by providing a Match Expression. The expression contains criteria that are checked against each User that wants to join the game and provides a mean for filtering players.

Let's clarify all this with an example. User Kermit has the following two User Variables set:

  • Rank: 10
  • BestScore: 2500

Kermit wants to play, so he chooses a public SFSGame and attempts to join it. Unfortunately the SFSGame expression is set as follows:

(Rank > 10) OR (BestScore > 3000)

Any attempt to join the Game will be refused because the player doesn't match the SFSGame criteria.

Creating a Room of type SFSGame is similar to creating a normal Room. On the client side we provide a CreateRoomRequest and a CreateSFSGameRequest , both taking a settings object: specifically RoomSettings and SFSGameSettings, respectively.

Here's a quick overview of the additional parameters that an SFSGame can use, compared to a regular Room:

  • isGamePublic: a public game can be joined by any player whose variables match the SFSGame player Match Expression. If no expression is used the game will be joinable by any User. Private games, instead, are based on invitations provided by the SFSGame creator (see invitedPlayers property below) so they usually don't need to specify a Match Expression.

  • minPlayersToStartGame: the minimum number of players to start the game. If the game is already running and the number of players goes below this limit the game will be stopped (see the notifyGameStartedViaRoomVariable property below).

  • invitedPlayers: (private games only) a list of players invited in the SFSGame. Each player will receive an invitation event and will be able to reply within the amount of time (see invitationExpiryTime property below).

  • searchableRooms: (private games only) a list of Rooms where the Game API can search for more players to invite. The API will look for more players if the number of invited players is not enough to reach the value of minPlayersToStartGame. This way you can add your friends to the game and let the system find more players to start it, if necessary. This mechanism works only when the game is started for the first time, not every time the number of users goes below the minimum value. If you need to search and invite more players every time the game stops you can do it via the SFSApi.findUsers() method.

  • leaveLastJoinedRoom: auto-remove players from their previous Room after successful join in case they received an invitation and accepted it.

  • playerMatchExpression: an expression to match players willing to play the game; by default no expression is used.

  • spectatorMatchExpression: an expression to match spectators willing to watch the game; by default no expression is used.

  • invitationExpiryTime: the amount of time allowed for invited players to accept / refuse.

  • invitationParams: optional custom parameters to be sent with the invitation. These could provide details about the inviter, the game, an invitation message, etc.

  • notifyGameStartedViaRoomVariable: automatically update a reserved Room Variable to signal that the game is started/stopped. The Room Variable uses the global setting to be broadcast outside of the Room. This can be used on the client side to show the game state in a list of available games. The reserved Room Variable names are found in the com.smartfoxserver.entities.variables.ReservedRoomVariables class.

Finally it is important to note that the SFSGame class extends SFSRoom and can be treated like any other Room in the system. SFSGame objects can be used and passed around to any method or function that works with the base Room interface (this is valid for both server and client side).

Quick join game

Another feature offered by the Game API (client and server) is the QuickJoinGame request. By providing a Match Expression and a list of Rooms (of type SFSGame) or a Room Group the system can search for matching Rooms and immediately teleport the player in the game action.

Here's an example using the client API:

// Prepare a match expression
var expr = new MatchExpression("rank", NumberMatch.GREATER_THAN, 3).And("rank", NumberMatch.LESS_THAN, 8);

// Provide an array of Room Groups where we want the search to take place
var whereToSearch = new List<string>(){"poker", "blackJack"};

// Fire the request and jump into the game!
sfs.Send(new QuickJoinGameRequest(expr, whereToSearch));

The above client code attempts to quickly join the user in any game from the poker or blackJack Room Groups where the game rank variable is greater than 3 and less than 8. Behind the scenes the system will also make sure that the Rooms are of type SFSGame and that there is at least one player slot available. If no Room matching these criteria is found a join error will be fired back at the client.

SFSGame only

The QuickJoinGame feature works exclusively with Rooms of type SFSGame (which supports Match Expressions); all other Room types will be ignored, when sending this request.