• Examples (Unity)
• Examples (iOS)
• Examples (Java/Android)
• Examples (C++)
Server API Documentation


» Buddy Messenger

» Overview

The Buddy Messenger example gives a demonstration of the client-side capabilities of the Buddy List API using Unity and SmartFoxServer 2X. It is fully compatible with the Buddy Messenger clients from the other APIs, which means users can communicate with one another even if they are on different clients and devices.

Using the Buddy List API, developers can add an instant messenger-like interface to any application, allowing users to see the status of friends (the so-called buddies) in their contact list and communicate with them regardless of the SmartFoxServer Room they are connected to (although they will need to know the user name to do so). In fact, in order to optimize the bandwidth usage in SmartFoxServer, messaging and user presence notifications are mostly limited to the users in the same Room. Using the buddy list system, this limit can be overridden in order to offer an improved user experience.

In this example, the screen-space overlay canvas of the Unity scene contains a sliding panel allowing the user to add new buddies by entering their name, remove buddies, block a buddy (to stop receiving status notifications and instant messages) and send him/her a message (a separate draggable panel is displayed whenever a new conversation is started by the user himself or by one of his buddies). The panel also shows the buddies state and their details.

In fact, using the separate sliding panel at the bottom, each user can change his own details and state as buddy to other users, thanks to the very flexible Buddy Variable objects featured by SmartFoxServer. Similarly to User Variables and Room Variables, Buddy Variables are stored on the server and broadcasted to the other clients. In particular, when set or updated, a Buddy Variable is broadcasted to all the users referenced in the buddy list of its owner.
Some Buddy Variables are predefined and reserved to store specific informations:

Buddy Variables can be online or offline. Offline variables can be accessed even if the user is not connected to SmartFoxServer (for example to store buddy details which are independent from the current session), while the online variables require the user presence. In our example the user's age is saved as an offline Buddy Variable, while his current mood as an online one.

>> DOWNLOAD the source files <<

» Setup & run

In order to setup and run the example, follow these steps:

  1. make sure your SmartFoxServer 2X installation contains the BasicExamples Zone definition;
  2. start SmartFoxServer 2X (v2.13 or later is highly recommended);
  3. start Unity (v2017.1 or later required);
  4. in the Projects panel click on the Open icon and browse to the /client/BuddyMessenger folder, then click the Open button;
  5. wait for the project setup completion (Unity needs to regenerate some libraries);
  6. go to the Project panel, click on the Assets folder and double click on the MainScene scene to open it;
  7. if SmartFoxServer and Unity are not running on the same machine, change the IP address of the server in the inspector of the Controller game object;
  8. click on the Play button to run the example in the Unity Editor, or go to the Build settings panel and build it for your target platform of choice.

All relevant assets are contained in the Assets/BuddyMessengerAssets folder; in particular the C# code is in the Scripts subfolder and the SmartFoxServer 2X client API DLLs are in the Plugins subfolder. Read the introduction to understand why multiple DLLs are used.

» Code highlights

Code for this example is contained in the script file called BuddyMessenger in the Scripts subfolder, attached to the Controller game object in the scene.
The structure of the file is a basic Unity C# script with a Start() and Update() methods. Additionally there are a number of listeners for the event generated by the UI components (mostly buttons), some helper methods and the listeners for the SmartFoxServer client API events.

» Connection and login

The connection and login approach followed in this example is very similar to the one from the Lobby example, which we recommend to review. The only difference is that we need some additional listeners for the BuddyList-related events.

	sfs.AddEventListener(SFSBuddyEvent.BUDDY_LIST_INIT, OnBuddyListInit);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_ERROR, OnBuddyError);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_ONLINE_STATE_UPDATE, OnBuddyListUpdate);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_VARIABLES_UPDATE, OnBuddyListUpdate);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_ADD, OnBuddyListUpdate);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_REMOVE, OnBuddyListUpdate);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_BLOCK, OnBuddyListUpdate);
	sfs.AddEventListener(SFSBuddyEvent.BUDDY_MESSAGE, OnBuddyMessage);

Most events are handled by the same method, OnBuddyListUpdate(), which rebuilds the buddy list in the UI from scratch. This has been done on purpose, to simplify the code. A more refined approach would update the specific list item to which each event refers, also discarding those events referring to the current user.

» Buddy list initialization and UI update

In order to make the buddy list system available in our game, the InitBuddyList request must be sent to the server after a successful login is performed (see the OnLogin() handler).

	sfs.Send(new Sfs2X.Requests.Buddylist.InitBuddyListRequest());

This causes the OnBuddyListInit event handler to be called, which takes care of populating the buddy list (see the OnBuddyListUpdate() handler below) and set in the UI the current user details (like nickname, state, and age) saved as offline Buddy Variables.

	private void OnBuddyListInit(BaseEvent evt) {
	    // Populate list of buddies
	    // Set current user details as buddy
	    // Nick
	    nickInput.text = (sfs.BuddyManager.MyNickName != null ? sfs.BuddyManager.MyNickName : "");
	    // States
	    foreach (string state in sfs.BuddyManager.BuddyStates) {
	        string stateValue = state;
	        GameObject newDropDownItem = Instantiate(stateItemPrefab) as GameObject;
	        BuddyStateItemButton stateItem = newDropDownItem.GetComponent<BuddyStateItemButton>();
	        stateItem.stateValue = stateValue;
	        stateItem.label.text = stateValue;
	        stateItem.button.onClick.AddListener(() => OnStateItemClick(stateValue));
	        newDropDownItem.transform.SetParent(stateDropDown, false);
	        // Set current state
	        if (sfs.BuddyManager.MyState == state) {
	    // Online
	    onlineToggle.isOn = sfs.BuddyManager.MyOnlineState;
	    // Buddy variables
	    BuddyVariable age = sfs.BuddyManager.GetMyVariable(BUDDYVAR_AGE);
	    ageInput.text = ((age != null && !age.IsNull()) ? Convert.ToString(age.GetIntValue()) : "");
	    BuddyVariable mood = sfs.BuddyManager.GetMyVariable(BUDDYVAR_MOOD);
	    moodInput.text = ((mood != null && !mood.IsNull()) ? mood.GetStringValue() : "");

The OnBuddyListUpdate() event handler is responsible of building (or re-building) the list of buddies displayed in the example's UI. This includes an image showing the state of the buddy, along with his name or nickname, age and mood (if set).

	private void OnBuddyListUpdate(BaseEvent evt) {
	    // Remove current list content
	    for (int i = buddyListContent.childCount - 1; i >= 0; --i) {
	    // Recreate list content
	    foreach (Buddy buddy in sfs.BuddyManager.BuddyList) {
	        GameObject newListItem = Instantiate(buddyListItemPrefab) as GameObject;
	        BuddyListItem buddylistItem = newListItem.GetComponent<BuddyListItem>();
	        // Nickname
	        buddylistItem.mainLabel.text = (buddy.NickName != null && buddy.NickName != "") ? buddy.NickName : buddy.Name;
	        // Age
	        BuddyVariable age = buddy.GetVariable(BuddyMessenger.BUDDYVAR_AGE);
	        buddylistItem.mainLabel.text += (age != null && !age.IsNull()) ? " (" + age.GetIntValue() + " yo)" : "";
	        // Mood
	        BuddyVariable mood = buddy.GetVariable(BuddyMessenger.BUDDYVAR_MOOD);
	        buddylistItem.moodLabel.text = (mood != null && !mood.IsNull()) ? mood.GetStringValue() : "";
	        // Icon
	        if (buddy.IsBlocked) {
	            buddylistItem.stateIcon.sprite = IconBlocked;
	            buddylistItem.chatButton.interactable = false;
	            buddylistItem.blockButton.transform.GetChild(0).GetComponentInChildren<Image>().sprite = IconUnblock;
	        } else {
	            buddylistItem.blockButton.transform.GetChild(0).GetComponentInChildren<Image>().sprite = IconBlock;
	            if (!buddy.IsOnline) {
	                buddylistItem.stateIcon.sprite = IconOffline;
	                buddylistItem.chatButton.interactable = false;
	            } else {
	                string state = buddy.State;
	                if (state == "Available")
	                    buddylistItem.stateIcon.sprite = IconAvailable;
	                else if (state == "Away")
	                    buddylistItem.stateIcon.sprite = IconAway;
	                else if (state == "Occupied")
	                    buddylistItem.stateIcon.sprite = IconOccupied;
	        // Buttons
	        string buddyName = buddy.Name; // Required or the listeners will always receive the last buddy name
	        buddylistItem.removeButton.onClick.AddListener(() => OnRemoveBuddyButtonClick(buddyName));
	        buddylistItem.blockButton.onClick.AddListener(() => OnBlockBuddyButtonClick(buddyName));
	        buddylistItem.chatButton.onClick.AddListener(() => OnChatBuddyButtonClick(buddyName));
	        buddylistItem.buddyName = buddyName;
	        // Add item to list
	        newListItem.transform.SetParent(buddyListContent, false);
	        // Also update chat panel if open
	        Transform panel = chatPanelsContainer.Find(buddyName);
	        if (panel != null) {
	            ChatPanel chatPanel = panel.GetComponent<ChatPanel>();
	            chatPanel.buddy = buddy;

» Add, remove, update and block buddies

The buddy list is recreated each time a buddy is added, removed, blocked, unblocked, his online/offline status changes or one of its Buddy Variables is updated. All these events are triggered by the user interaction, through the respective requests sent to SmartFoxServer like the following examples show.

Add buddy (see OnAddBuddyButtonClick() method):

	if (buddyInput.text != "") {
	    sfs.Send(new Sfs2X.Requests.Buddylist.AddBuddyRequest(buddyInput.text));
	    buddyInput.text = "";

Block/unblock buddy (see OnBlockBuddyButtonClick() method):

	bool isBlocked = sfs.BuddyManager.GetBuddyByName(buddyName).IsBlocked;
	sfs.Send(new Sfs2X.Requests.Buddylist.BlockBuddyRequest(buddyName, !isBlocked));

Set user nickname, age, mood or state (see OnSetDetailsButtonClick() method):

	List<BuddyVariable> buddyVars = new List<BuddyVariable>();
	buddyVars.Add(new SFSBuddyVariable(ReservedBuddyVariables.BV_NICKNAME, nickInput.text));
	buddyVars.Add(new SFSBuddyVariable(BUDDYVAR_AGE, Convert.ToInt32(ageInput.text)));
	buddyVars.Add(new SFSBuddyVariable(BUDDYVAR_MOOD, moodInput.text));
	buddyVars.Add(new SFSBuddyVariable(ReservedBuddyVariables.BV_STATE, currentState));
	sfs.Send(new Sfs2X.Requests.Buddylist.SetBuddyVariablesRequest(buddyVars));

» Exchanging messages with buddies

When clicking on the chat icon in the buddy list, a draggable panel is displayed in the screen-space overlay, to start a conversation with the related buddy (if he/she is online in the buddy list system). By means of the input field and Send button available on the panel, a message can be sent with a BuddyMessage request.

	ChatPanel chatPanel = panel.GetComponent<ChatPanel>();
	string message = chatPanel.messageInput.text;
	// Add a custom parameter containing the recipient name,
	// so that we are able to write messages in the proper chat tab
	ISFSObject _params = new SFSObject();
	_params.PutUtfString("recipient", buddyName);
	Buddy buddy = sfs.BuddyManager.GetBuddyByName(buddyName);
	sfs.Send(new Sfs2X.Requests.Buddylist.BuddyMessageRequest(message, buddy, _params));
	chatPanel.messageInput.text = "";

Note that the custom parameter "recipient" is added to the request, set to the name of the message recipient. This is useful in the OnBuddyMessage() handler to determine in which chat panel (if more than one is open) the message must be displayed when the sender is the current user.

	private void OnBuddyMessage(BaseEvent evt) {
	    bool isItMe = (bool)evt.Params["isItMe"];
	    Buddy sender = (Buddy)evt.Params["buddy"];
	    string message = (string)evt.Params["message"];
	    Buddy buddy;
	    if (isItMe)
	        string buddyName = (evt.Params["data"] as ISFSObject).GetUtfString("recipient");
	        buddy = sfs.BuddyManager.GetBuddyByName(buddyName);
	        buddy = sender;
	    if (buddy != null) {
	        // Open panel if needed
	        // Print message
	        Transform panel = chatPanelsContainer.Find(buddy.Name);
	        ChatPanel chatPanel = panel.GetComponent<ChatPanel>();
	        chatPanel.addMessage("<b>" + (isItMe ? "You" : buddy.Name) + ":</b> " + message);

To see other advanced uses of SmartFoxServer you can now move onwards to the next examples.

You should also read the comments to methods and properties in the example source code for additional informations and possible code optimizations.

» More resources

You can learn more about the SmartFoxServer basics by consulting the following resources: