This guide explains how to use the Simple Multiplayer (SMP) for Actionscript3. The multiplayer system works like a relay in that it helps clients send messages to each other. Players are then able to interact with each other as messages are transmitted to the server and to other clients. The SMP service is provided at no cost. The only requirement is that the game also use at least 2 other user features. For example, a game can use multierplayer, login, high scores and/or achievements.

Important Limitations

  • It is recommended that the game be loaded remotely. So when errors happen, they can be fixed even after the game has been distributed. Players with errors could cause problems for players on the latest version.
  • There is no server side code available to developers. Players must be able to synchronize all shared data with each other. Turned based, racing, billards will work well with this but an MMO won’t.
  • There is no global storage system, individual player data can only be stored using online saves.
  • Room size is limited to 100 people per a lobby and 10 people per a game room. Game rooms can provide realtime data while a lobby is for connecting players and limited messages like a chat room.

Getting Started

Step 1 is to make a callback function after the Game API is loaded. All multiplayer data will go through the callback function. Use the single argument is initSMP to tell SMP what function is the callback.

function handleSDK(e:Event) {
	if (sdk.type == 'gameapiloaded') {
		sdk.initSMP(smp);
	}
}

function smp(msg){
	// multiplayer code goes here
}

Step 2 is to wait for the first message, it will have the start action. In the example, we join a room with a randomly generated name. If one already exists we join it. If no room is available, we create one and then join. Once in the room, we broadcast a hello message and wait for others to broadcast the same.

Note, the started varible is used because a room could be on a different server. If this is the case, SMP will automagically connect to the right server or node. Without this check, the code would run twice as the start action happens again on server switch.

var started = false; // keep track if we already started or are reconnecting to a new server
function smp(msg){ // the callback function
	if (msg.action == 'start' && !started) { // do this on the first start
		started = true;
		sdk.multiplayer.roomList('lobby', null, null, 'lookup');
	}

	if (msg.section == 'rooms' && msg.action == 'list' && msg.pt == 'lookup') {
		if(msg.rooms.length > 0){ // if the room we want exists, join it
			sdk.multiplayer.roomJoin(msg.rooms[0].roomid, msg.rooms[0].node, 'inroom');
		}else{ // if not, create it
			sdk.multiplayer.roomCreate('lobby', null, null, 'nowjoin');
		}
	}

	if (msg.section == 'rooms' && msg.action == 'create' && msg.pt == 'nowjoin') {
		// if we created a room, we will want to also join it
		sdk.multiplayer.roomJoin(msg.room.roomid, msg.room.node, 'inroom');
	}

	if (msg.section == 'rooms' && msg.action == 'join' && msg.pt == 'inroom') {
		// finally let's announce that we have arrived.
		sdk.multiplayer.broadcast({say: 'hello room'});
	}

	if (msg.action == 'broadcast') {
		// listen for other clients
		trace(msg.say);
	}

	if (msg.section == 'rooms' && msg.action == 'playerjoined') {
		trace('playerjoined', msg)
	}
		
	if (msg.section == 'rooms' && msg.action == 'playerleft') {
		trace('playerleft', msg)
	}

	trace('-----');
}

Step 3 is to continue building your message chain. Use the pass-through argument to separate similar calls and to keep track of what step should follow next with your own game logic. Read the reference below to understand the functions available. Once you have finished step 2, open 2 of the same swf and check for the ‘Hello room’ message in the first loaded client. You may need to set up a Trusted Folder to load the 2nd swf from your local computer without security errors.

Reference

Room List

sdk.multiplayer.roomList(type, roomid, custom, passthrough)

Will list game rooms based on the arguments provided.

  • type: (optional) A string equalling ‘lobby’ or ‘game’
  • roomid: (optional) A string of a specific room
  • custom: (optional) A object to sort room list. See room create.
  • passthrough: (optional) A string less than 50 characters to be passed back to the callback

Room Join

sdk.multiplayer.roomJoin(roomid, node, passthrough)

Will list game rooms based on the arguments provided.

  • roomid: A string of a specific room
  • node: A node returned from room list or room create that identifies which server the room is in
  • passthrough: (optional) A string less than 50 characters to be passed back to the callback

Room Create

sdk.multiplayer.roomCreate(type, roomid, custom, passthrough, options)

Create a new room. Note, this does not automatically join the room. Also, if setting the roomid manually, the roomid could be in use by another application. This is a known bug.

  • type: (optional)(default: ‘lobby’) A string equalling ‘lobby’ or ‘game’
  • roomid: (optional)(default: ‘random string’) A string to identitfy the room by.
  • custom: (optional) A object to store custom data or to provide extra sorting options
  • passthrough: (optional) A string less than 50 characters to be passed back to the callback
  • options: (optional) An object containing one or more key value pairs
    • isOpen: Boolean value of false will prevent other players from joining
    • isVisible: Boolean value of false will prevent a room from being list
    • maxPlayers: An integer of max players allowed in a room

Room Update

sdk.multiplayer.roomUpdate(custom, passthrough, options)

Update the custom varible and/or options of a room. This should be used infrequently and not for realtime updates.

  • custom: (optional) A object to store custom data or to provide extra sorting options
  • passthrough: (optional) A string less than 50 characters to be passed back to the callback
  • options: (optional) An object containing one or more key value pairs
    • isOpen: Boolean value of false will prevent other players from joining
    • isVisible: Boolean value of false will prevent a room from being list

Room Leave

sdk.multiplayer.roomLeave(passthrough)

The player will exit the room they are in

  • passthrough: (optional) A string less than 50 characters to be passed back to the callback

Room Broadcast

sdk.multiplayer.broadcast(message)

Send a message to everyone in a room except to the person sending it.

  • message: An object containing data to be shared with a room

Room Broadcast All

sdk.multiplayer.broadcastAll(message)

Send a message to everyone in a room and return the message to the sender via the callback.

  • message: An object containing data to be shared with a room

Room Send To

sdk.multiplayer.sendTo(userid, message)

Send a message to single person is the same room as the sender.

  • playerid: A string to identify a player by. It can be found in room list
  • message: An object containing data to be shared with another player

User Meta Data

sdk.multiplayer.userMeta(meta, passthrough)

User data visible to other players in a room. Remember to set this on each start as joining a room could cause the player to switch servers.

  • meta: Data to be stored along with the player
  • passthrough: (optional) A string less than 50 characters to be passed back to the callback

Ping

sdk.multiplayer.ping(passthrough)

Will return a action of ‘pong’ to be used with a timer to calculate latency.

  • passthrough: (optional) A string less than 50 characters to be passed back to the callback

debugLevel

sdk.multiplayer.debugLevel = Integer

Will limit what is output to the console. Useful when you need to hide some output for performance or production use.

  • Integer: Using 2 will output everything. 1 output everything except broadcast messages. 0 will be silent except for errors.

Disconnects

Players will be disconnected after 15 minutes of inactivity. Players could also be disconnected because of networking problems or server maintenance. When a disconnect is detected, a callback with section connection and action disconnect will be sent to the game. If the returned errorcode property is 4000 it was a timeout. Otherwise, if the errorcode is 1, the connection was lost for an unknown reason. Games need to trigger a message for the player and return them to a main menu or instruct them to reload the game.

Troubleshooting

Multiplayer logic will become a mess quickly. Keep the code clean and concise to avoid trouble later. When you struggle to understand what is going on, carefully read the output to track what is happening during the logic chain. Use the pass-through arguments to force your chain to follow the path you need.

As noted earlier, there is more than one server or node. When a room is created, it will be put on the least congested server. Be prepared to see output showing this server switching. Also, remember to expect this behavior to avoid getting stuck in a loop.

About room names, note that name conflicts can happen between different games. If you want to name a room manually, prefix the name with a unique value to avoid possible conflicts. Otherwise, leave the room name as null and an id will be generated automatically.

Final Notes for Success

Communication

Getting a player into a game room and playing involves a number of steps. Remember to tell the player what is happening along the way. Tell them when they are connecting, waiting for another player, and any other part of your games multiplayer logic.

Player Onboarding

Getting players into the right room quickly will be a big challenge. To help, we have made the Matchmaking system. You should use it for auto joining games because it has features to prevent 2 players from being stuck in seperate rooms waiting for antoher player.

Stay Simple

Your multiplayer code should be very simple with very little game logic mixed in. Use functions to other classes to keep your In and Out code separated. Also, keep the data you send using SMP small. For example {rotation: 5.123345345} could be shortened to {r: 5}, this helps keep the data flowing quickly.

Distribution

Multiplayer games likely will need to be updated after being released like single player games. However, having more than one version of a game could cause errors. For Flash, we highly recommend using an auto loading system to allow distributed games to be updated after release. Please contact us as we can help by providing example and a storage location.