Access
Connect cross-platform accounts & identity management
using AccelByte.Api;
using AccelByte.Core;
using AccelByte.Models;
AccelBytePlugin.GetLobby().FriendsStatusChanged += result =>{};
AccelBytePlugin.GetLobby().FriendRequestAccepted += result =>{};
AccelBytePlugin.GetLobby().OnIncomingFriendRequest += result =>{};
AccelBytePlugin.GetLobby().OnUnfriend += result =>{};
AccelBytePlugin.GetLobby().FriendRequestCanceled += result =>{};
AccelBytePlugin.GetLobby().FriendRequestRejected += result =>{};
AccelBytePlugin.GetLobby().RequestFriend(userInfo.userId, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to send a friends request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Sent Friends Request");
}
});
AccelBytePlugin.GetLobby().Unfriend(userId, result =>
{
// Check this is an error
if (result.IsError)
{
Debug.Log($"Failed to unfriend a friend: code: {result.Error.Code}, message: {result.Error.Message}");
}
else
{
Debug.Log("Successfully unfriend a friend!");
}
});
AccelBytePlugin.GetLobby().LoadFriendsList(result =>
{
// Check this is not an error
if (!result.IsError)
{
foreach (string friendID in result.Value.friendsId)
{
Debug.Log($"Friend : {friendID}");
}
}
else
{
Debug.LogWarning("Error in Getting Friends");
}
});
// Get all Incoming Friend Requests
AccelBytePlugin.GetLobby().ListIncomingFriends(result =>
{
// Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Incoming Requests Code: {result.Error.Code}, Message: {result.Error.Message}");
}
else
{
// List incoming friends
Debug.Log("Get list incoming friends is successfully");
}
});
// Get all Outgoing Friend Requests
AccelBytePlugin.GetLobby().ListOutgoingFriends(result =>
{
// Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Outgoing Friend Lists Code: {result.Error.Code}, Message: {result.Error.Message}");
}
else
{
// List outgoing friends
Debug.Log("Get list outgoing friends is successfully");
}
});
AccelBytePlugin.GetUser().GetUserByUserId(friendID, x =>
{
//Do something with the user Data
});
AccelBytePlugin.GetUser().SearchUsers(query, result =>
{
if (!result.IsError)
{
// List UserID's Found using Query
}
else
{
Debug.LogWarning($"Unable to Query Users Code: {result.Error.Code}, Message: {result.Error.Message}");
}
});
In this tutorial, you will learn how to use the Friend service. This guide assumes that you have already implemented the Lobby Services (opens new window).
This guide will be more abstract than the previous guides as the specifics for how each game will implement Friends can vary dramatically. Skip to the Step by Step (opens new window) section to see how we implemented each feature in our tutorial project.
There are a handful of concepts and classes to familiarize yourself with (you can find most of these classes within the UserModels.cs file inside the plugin SDK).
AccelByte’s SDK uses a mixture of Websocket and HTTP requests, generally presented to you through a wrapper layer that uses callbacks and actions to return your data. Because of this, you must design your UI to accommodate delayed callbacks and, sometimes, several layers of callbacks (e.g., requesting a list of Friends > Requesting specific data about friends > Requesting the avatar of a friend).
We will start by adding simple friend logic into the game.
Create a new script called FriendManagementHandler.cs and attach it to the AccelByteHandler gameObject.
Add the following AccelByte Libraries to the top of the script:
using AccelByte.Api;
using AccelByte.Models;
using AccelByte.Core;
void AddFriend(string displayName)
{
AccelBytePlugin.GetUser().SearchUsers(displayName, result =>
{
// If not an error
if (!result.IsError)
{
foreach (PublicUserInfo userInfo in result.Value.data)
{
// Check if display name text has a same value as the result
if (userInfo.displayName == query)
{
AccelBytePlugin.GetLobby().RequestFriend(userInfo.userId, addResult =>
{
if (addResult.IsError)
{
Debug.Log($"Failed to send a friends request: error code: {addResult.Error.Code} message: {addResult.Error.Message}");
}
else
{
Debug.Log("Sent Friends Request");
}
});
}
else
{
Debug.Log("User is not found");
}
}
}
else
{
Debug.LogWarning($"Unable to Query Users Code: {result.Error.Code}, Message: {result.Error.Message}");
}
});
}
private void DisplayPending()
{
// Get all Incoming Friend Requests
AccelBytePlugin.GetLobby().ListIncomingFriends(result =>
{
// Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Incoming Requests Code: {result.Error.Code}, Message: {result.Error.Message}");
}
else
{
// Loop through all the UserID's returned by the Friends callback and get their PublicUserData
foreach (string userID in result.Value.friendsId)
{
// Request the PublicUserData for the specific Friend
AccelBytePlugin.GetUser().GetUserByUserId(userID, userResult =>
{
// If it's an Error, report it and do nothing else
if (userResult.IsError)
{
Debug.LogWarning($"Unable to User Code: {userResult.Error.Code}, Message: {userResult.Error.Message}");
}
// If we have valid data, log the display name
else
{
Debug.Log($"Friend request from : {userResult.Value.displayName}");
}
});
}
}
});
// Get all Outgoing Friend Requests
AccelBytePlugin.GetLobby().ListOutgoingFriends(result =>
{
// Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Outgoing Friend Lists Code: {result.Error.Code}, Message: {result.Error.Message}");
}
else
{
// Loop through all the UserID's returned by the Friends callback and get their PublicUserData
foreach (string userID in result.Value.friendsId)
{
// Request the PublicUserData for the specific Friend
AccelBytePlugin.GetUser().GetUserByUserId(userID, userResult =>
{
// If it's an Error, report it and do nothing else
if (userResult.IsError)
{
Debug.LogWarning($"Unable to User Code: {userResult.Error.Code}, Message: {userResult.Error.Message}");
}
// If we have valid data, log the display name
else
{
Debug.Log($"Pending Friend Request to : {userResult.Value.displayName}");
}
});
}
}
});
}
private void GetFriends()
{
AccelBytePlugin.GetLobby().LoadFriendsList(result =>
{
//Check this is not an error
if (!result.IsError)
{
//Check if no friends were returned
if (result.Value.friendsId.Length <= 0)
{
return;
}
//Fire off Requests to create UI for each friend
Debug.Log("Loaded Friends List Successfully");
List<string> userIds = new List<string>();
foreach (string friendID in result.Value.friendsId)
{
userIds.Add(friendID);
}
AccelBytePlugin.GetLobby().BulkGetUserPresence(userIds.ToArray(), bulkResult =>
{
if (!bulkResult.IsError)
{
foreach (var friend in bulkResult.Value.data)
{
AccelBytePlugin.GetUser().GetUserByUserId(friend.userID, x =>
{
Debug.Log($"Friend : {x.Value.displayName}, Status : {friend.activity}, and Availability : {friend.availability.ToString()}");
});
}
}
});
}
else
{
Debug.LogWarning("Error in Getting Friends");
}
});
}
private void Unfriend(string userId)
{
AccelBytePlugin.GetLobby().Unfriend(userId, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to unfriend a friend: code: {result.Error.Code}, message: {result.Error.Message}");
}
else
{
Debug.Log("Successfully unfriend a friend!");
}
});
}
This event is triggered if a friend’s activity or availability status changes.
AccelBytePlugin.GetLobby().FriendsStatusChanged += result =>
{
Debug.Log($"Friend status change into status : {result.Value.activity} and availability : {result.Value.availability} from user : {result.Value.userID}");
};
This event is triggered if a pending Friend Request is accepted by another player.
AccelBytePlugin.GetLobby().FriendRequestAccepted += result =>
{
Debug.Log($"Accepted a Friend Request from user {result.Value.friendId}");
};
This event is triggered if someone adds the player as a Friend.
AccelBytePlugin.GetLobby().OnIncomingFriendRequest += result =>
{
Debug.Log($"Received a Friend Request from user {result.Value.friendId}");
};
This event is triggered if the player is unfriended by a Friend.
AccelBytePlugin.GetLobby().OnUnfriend += result =>
{
Debug.Log($"Unfriended User {result.Value.friendId}");
};
This event is triggered if an Incoming Friend Request is canceled by the requesting player.
AccelBytePlugin.GetLobby().FriendRequestCanceled += result =>
{
Debug.Log($"Cancelled a Friend Request from user {result.Value.userId}");
};
This event is triggered if the player’s Friend Request is rejected by another player.
AccelBytePlugin.GetLobby().FriendRequestRejected += result =>
{
Debug.Log($"Rejected a Friend Request from user {result.Value.userId}");
};
Congratulations! You have successfully implemented the basics of the Friends service!
Continue on for a step by step example of the UI and code implementation. Otherwise, you are now ready to move on to Party services (opens new window).
For the Friends Page, create a new panel or scene with the following objects:
Since the Friends Page will have a lot of items to display, we have divided the page into three sections: Friends, Pending, and Blocked. To do this in your own game, add the following UI objects:
You can add the UIs into separate panels, such as in the example below:
Move to the tab panels. Here, we will prepare the page to list all the Friends items. Add the following to each tab panel:
Friends tab panel:
Once completed, create a new panel, parent it to Friends List panel, and add the following UIs:
Below is an example view of the Friends tab panel, along with its hierarchy:
Pending tab panel:
Incoming Request List:
Create a new panel, parent it to the Incoming Pending Requests list panel, and add the following UI elements:
Outgoing Request List:
Create a new panel, parent it to the Incoming Pending Requests list panel, and add the following UI elements:
Below is an example view of the Pending tab panel, along with its hierarchy:
Blocked tab panel:
Create a new panel, parent it to the Incoming Blocked Players list panel, and add the following UI elements:
Below is an example view of the Blocked tab panel, along with its hierarchy:
Lastly, for the Search Friends pop-up, create a new panel, and add the following UI elements:
Create a new panel, parent it to the Incoming Blocked Players list panel, and add the following UI elements:
Below is an example view of the Search Friends pop-up, along with its hierarchy:
To make it easier to move to another panel, create a new menu panel and add the following UI elements:
Go to the FriendsManagementHandler.cs script. Remove the AddFriend and Unfriend functions that you have previously created. We'll add these functionalities later to another function with additional improvement.
Add the following AccelByte and UnityEngine libraries to the top of the script:
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine.UI;
using UnityEngine.Serialization;
To avoid ambiguous references, add this code to the top of the script:
using Button = UnityEngine.UI.Button;
private Dictionary<string, FriendStatusPanel> friendUIDictionary = new Dictionary<string, FriendStatusPanel>();
[Header("Panels")]
public GameObject FriendsManagementWindow;
[FormerlySerializedAs("FriendsPanel")]
[SerializeField]
private RectTransform friendsPanel;
[SerializeField]
private RectTransform requestsPanel;
[SerializeField]
private RectTransform blockedPanel;
#region Buttons
[Header("Buttons")]
[SerializeField]
private Button friendsTabButton;
[SerializeField]
private Button pendingTabButton;
[SerializeField]
private Button blockedTabButton;
[SerializeField]
private Button exitButton;
#endregion
[Header("Friends Panel")]
[SerializeField]
private Transform friendsDisplayPanel;
[FormerlySerializedAs("FriendsDisplayPrefab")]
[SerializeField]
private GameObject friendsDisplayPrefab;
[SerializeField]
private Button friendsSearchButton;
[SerializeField]
private Transform friendsDisplayPlaceholder;
#region Search
[Header("Search Panel")]
[SerializeField]
private GameObject addFriendsPrefab;
[SerializeField]
private Transform friendsSearchPanel;
[SerializeField]
private InputField friendsSearchInputField;
[SerializeField]
private RectTransform friendsSearchScrollView;
[SerializeField]
private Button friendsSearchQuitButton;
[SerializeField]
private Transform friendsSearchPlaceholder;
#endregion
#region Pending
[Header("Pending Panel")]
[SerializeField]
private RectTransform pendingIncomingRequestsContent;
[SerializeField]
private RectTransform pendingOutgoingRequestsContent;
[SerializeField]
private GameObject pendingIncomingRequestsPrefab;
[SerializeField]
private GameObject pendingOutgoingRequestsPrefab;
[SerializeField]
private Transform pendingIncomingRequestPlaceholder;
[SerializeField]
private Transform pendingOutgoingRequestPlaceholder;
[SerializeField]
private Text pendingIncomingRequestText;
[SerializeField]
private Text pendingOutgoingRequestText;
#endregion
#region Blocked
[Header("Blocked")]
[SerializeField]
private RectTransform blockedContent;
[SerializeField]
private GameObject blockedUserPrefab;
[SerializeField]
private Transform blockedDisplayPlaceholder;
#endregion
/// A utility function to Destroy all Children of the parent transform. Optionally do not remove a specific Transform
/// <param name="parent">Parent Object to destroy children</param>
/// <param name="doNotRemove">Optional specified Transform that should NOT be destroyed</param>
private static void LoopThroughTransformAndDestroy(Transform parent, Transform doNotRemove = null)
{
//Loop through all the children and add them to a List to then be deleted
List<GameObject> toBeDeleted = new List<GameObject>();
foreach (Transform t in parent)
{
//except the Do Not Remove transform if there is one
if (t != doNotRemove)
{
toBeDeleted.Add(t.gameObject);
}
}
//Loop through list and Delete all Children
for (int i = 0; i < toBeDeleted.Count; i++)
{
Destroy(toBeDeleted[i]);
}
}
private void DisplayBlocked()
{
//Cleanup First
LoopThroughTransformAndDestroy(blockedContent.transform,blockedDisplayPlaceholder);
//Get Blocked List
AccelBytePlugin.GetLobby().GetListOfBlockedUser(result =>
{
//Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Blocked Player List Code: {result.Error.Code}, Message: {result.Error.Message}");
blockedDisplayPlaceholder.gameObject.SetActive(true);
}
else
{
blockedDisplayPlaceholder.gameObject.SetActive(false);
//Loop through all the UserID's returned by the callback and get their PublicUserData
foreach (BlockedData blockedUser in result.Value.data)
{
//Request the PublicUserData for the specific User
AccelBytePlugin.GetUser().GetUserByUserId(blockedUser.blockedUserId, userResult =>
{
//If it's an Error, report it and do nothing else
if (userResult.IsError)
{
Debug.LogWarning($"Unable to User Code: {userResult.Error.Code}, Message: {userResult.Error.Message}");
}
});
}
}
});
}
public enum FriendsMode
{
Default,
Friends,
Pending,
Blocked
};
private FriendsMode _displayMode = FriendsMode.Default;
private FriendsMode DisplayMode
{
get => _displayMode;
set
{
switch (value)
{
case FriendsMode.Default:
friendsPanel.gameObject.SetActive(true);
requestsPanel.gameObject.SetActive(false);
blockedPanel.gameObject.SetActive(false);
break;
case FriendsMode.Friends:
friendsPanel.gameObject.SetActive(true);
requestsPanel.gameObject.SetActive(false);
blockedPanel.gameObject.SetActive(false);
GetFriends();
break;
case FriendsMode.Pending:
requestsPanel.gameObject.SetActive(true);
friendsPanel.gameObject.SetActive(false);
blockedPanel.gameObject.SetActive(false);
DisplayPending();
break;
case FriendsMode.Blocked:
blockedPanel.gameObject.SetActive(true);
friendsPanel.gameObject.SetActive(false);
requestsPanel.gameObject.SetActive(false);
DisplayBlocked();
break;
}
}
}
private void SearchForFriends(string query)
{
AccelBytePlugin.GetUser().SearchUsers(query, result =>
{
if (!result.IsError)
{
ListQueriedusers(result.Value);
}
else
{
Debug.LogWarning($"Unable to Query Users Code: {result.Error.Code}, Message: {result.Error.Message}");
}
});
}
private void ListQueriedusers(PagedPublicUsersInfo pagedInfo)
{
//Cleanup First
LoopThroughTransformAndDestroy(friendsSearchScrollView.transform, friendsSearchPlaceholder);
if (pagedInfo.data.Length <=0)
{
friendsSearchPlaceholder.gameObject.SetActive(true);
}
else
{
friendsSearchPlaceholder.gameObject.SetActive(false);
foreach (PublicUserInfo info in pagedInfo.data)
{
FriendsAddPanel addPanel = Instantiate(addFriendsPrefab,friendsSearchScrollView).GetComponent<FriendsAddPanel>();
addPanel.Create(info);
}
}
}
private void DisplaySearch()
{
friendsSearchPanel.gameObject.SetActive(true);
LoopThroughTransformAndDestroy(friendsSearchScrollView.transform, friendsSearchPlaceholder);
friendsSearchPlaceholder.gameObject.SetActive(true);
}
public void UpdateFriends(FriendsStatusNotif notification)
{
//Find the friend and update it's UI
if (friendUIDictionary.ContainsKey(notification.userID))
{
friendUIDictionary[notification.userID].UpdateUser(notification);
}
//Otherwise We should handle this in some way, possibly creating a Friend UI Piece
else
{
Debug.Log("Unregistered Friend received a Notification");
}
}
/// Called when friend status is changed
public void OnFriendsStatusChanged(Result<FriendsStatusNotif> result)
{
GetComponent<FriendsManagementHandler>().UpdateFriends(result.Value);
}
You can create more functions for other events and use the debug log to verify if there are any updates.
/// Called when friend request is accepted
public void OnFriendRequestAccepted(Result<Friend> result)
{
Debug.Log($"Accepted a Friend Request from user {result.Value.friendId}");
}
/// Called when there is incoming friend request
public void OnIncomingFriendRequest(Result<Friend> result)
{
Debug.Log($"Received a Friend Request from user {result.Value.friendId}");
}
/// Called when friend is unfriend
public void OnUnfriend(Result<Friend> result)
{
Debug.Log($"Unfriended User {result.Value.friendId}");
}
/// Called when friend request is canceled
public void OnFriendRequestCanceled(Result<Acquaintance> result)
{
Debug.Log($"Cancelled a Friend Request from user {result.Value.userId}");
}
/// Called when friend request is rejected
public void OnFriendRequestRejected(Result<Acquaintance> result)
{
Debug.Log($"Rejected a Friend Request from user {result.Value.userId}");
}
public Transform Menu;
public Button FriendsButton;
private bool initialize = false;
public void Create()
{
if (initialize) return;
initialize = true;
}
public void ConnectToLobby()
{
...
//Init menu handler
GetComponent<MenuHandler>().Create();
GetComponent<MenuHandler>().Menu.gameObject.SetActive(true);
...
//Friends
_lobby.FriendsStatusChanged += notificationHandler.OnFriendsStatusChanged;
_lobby.FriendRequestAccepted += notificationHandler.OnFriendRequestAccepted;
_lobby.OnIncomingFriendRequest += notificationHandler.OnIncomingFriendRequest;
_lobby.FriendRequestCanceled += notificationHandler.OnFriendRequestCanceled;
_lobby.FriendRequestRejected += notificationHandler.OnFriendRequestRejected;
_lobby.OnUnfriend += notificationHandler.OnUnfriend;
...
}
public void RemoveLobbyListeners()
{
...
//Friends
_lobby.FriendsStatusChanged -= notificationHandler.OnFriendsStatusChanged;
_lobby.FriendRequestAccepted -= notificationHandler.OnFriendRequestAccepted;
_lobby.OnIncomingFriendRequest -= notificationHandler.OnIncomingFriendRequest;
_lobby.FriendRequestCanceled -= notificationHandler.OnFriendRequestCanceled;
_lobby.FriendRequestRejected -= notificationHandler.OnFriendRequestRejected;
_lobby.OnUnfriend -= notificationHandler.OnUnfriend;
}
private bool setupStatus = false;
...
public void Setup()
{
// reset the exit button's listener, then add the listener based on the exit screen type
exitButton.onClick.RemoveAllListeners();
exitButton.onClick.AddListener(() =>
{
FriendsManagementWindow.SetActive(false);
GetComponent<MenuHandler>().Menu.gameObject.SetActive(true);
});
// Check whether the FriendsPanel already set up or not
if (setupStatus)
{
DisplayMode = FriendsMode.Default;
return;
}
// Run the setup if it still hasn't
else
{
setupStatus = true;
DisplayMode = FriendsMode.Friends;
// reset listeners, so it won't triggered more than once
friendsTabButton.onClick.RemoveAllListeners();
pendingTabButton.onClick.RemoveAllListeners();
blockedTabButton.onClick.RemoveAllListeners();
// add the listeners
friendsTabButton.onClick.AddListener(() => DisplayMode = FriendsMode.Friends);
pendingTabButton.onClick.AddListener(() => DisplayMode = FriendsMode.Pending);
blockedTabButton.onClick.AddListener(() => DisplayMode = FriendsMode.Blocked);
friendsSearchPanel.gameObject.SetActive(false);
friendsDisplayPlaceholder.gameObject.SetActive(true);
friendsSearchQuitButton.onClick.AddListener(() => friendsSearchPanel.gameObject.SetActive(false));
friendsSearchButton.onClick.AddListener(DisplaySearch);
friendsSearchInputField.onEndEdit.AddListener(SearchForFriends);
friendsSearchButton.onClick.AddListener(() => friendsSearchPanel.gameObject.SetActive(true));
}
}
public void Create()
{
...
FriendsButton.onClick.AddListener(() =>
{
GetComponent<FriendsManagementHandler>().Setup();
Menu.gameObject.SetActive(false);
GetComponent<FriendsManagementHandler>().FriendsManagementWindow.SetActive(true);
});
}
Create a new script called FriendStatusPanel.cs and attach it to the FriendDisplay prefab.
Add the following AccelByte and UnityEngine libraries to the top of the script:
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
To avoid ambiguous references, add this code to the top of the script:
using Image = UnityEngine.UI.Image;
[SerializeField]
private Image profilePicture;
[SerializeField]
private Image statusDisplay;
[SerializeField]
private Button chatButton;
[SerializeField]
private Button inviteToPartyButton;
[SerializeField]
private Button unfriendButton;
[SerializeField]
private Button blockButton;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Text onlineStatusText;
Once completed, create a variable that will hold the User Data:
PublicUserData _userData;
public void SetOnlineStatus(FriendsStatusNotif notification)
{
switch (notification.availability)
{
case "offline":
onlineStatusText.text = "Offline";
statusDisplay.color = Color.black;
break;
case "online":
onlineStatusText.text = "Online";
statusDisplay.color = Color.green;
break;
case "busy":
onlineStatusText.text = "Busy";
statusDisplay.color = Color.yellow;
break;
case "invisible":
onlineStatusText.text = "Offline";
statusDisplay.color = Color.black;
break;
default:
onlineStatusText.text = $"INVALID UNHANDLED {notification.availability}";
statusDisplay.color = Color.magenta;
break;
}
Debug.Log($"Friend Status for {notification.userID} changed to {notification.availability}");
}
public void Create(PublicUserData pud)
{
_userData = pud;
displayNameText.text = _userData.displayName;
}
public void SetupButton()
{
unfriendButton.onClick.AddListener(() =>
{
AccelBytePlugin.GetLobby().Unfriend(_userData.userId, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to unfriend a friend: code: {result.Error.Code}, message: {result.Error.Message}");
}
else
{
Debug.Log("Successfully unfriend a friend!");
LobbyHandler.Instance.GetComponent<FriendsManagementHandler>().RefreshFriendsList();
}
});
});
}
Create a script called FriendIncomingPanel.cs.
Add the following AccelByte and UnityEngine Libraries to the top of the script:
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button acceptFriendButton;
[SerializeField]
private Button declineFriendButton;
[SerializeField]
private Button blockFriendButton;
private PublicUserData _userData;
/// An initialisation Function required to be called to Populate the UI appropriately
public void Create(PublicUserData userData)
{
//Cache the PublicUserData
_userData = userData;
//Set the Display Name
displayNameText.text = _userData.displayName;
//Setup the Button to Accept a Friend Request
acceptFriendButton.onClick.AddListener(() =>
{
//Make the Call to Accept the Friend Request using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().AcceptFriend(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to accept a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Accepted Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
//Setup the Button to Decline a Friend Request
declineFriendButton.onClick.AddListener(() =>
{
//Make the Call to Decline the Friend Request using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().RejectFriend(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to decline a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Declined Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
//Setup the Button to Block a Player
blockFriendButton.onClick.AddListener(() =>
{
//Make the Call to Block a Player using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().BlockPlayer(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to block a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Block Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
}
Create a script called FriendsOutgoingPanel.cs.
Add the following AccelByte and UnityEngine libraries to the top of the script:
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button cancelRequestButton;
private PublicUserData _userData;
public void Create(PublicUserData userData)
{
//Cache the PublicUserData
_userData = userData;
//Set the Display Name
displayNameText.text = _userData.displayName;
//Setup the Button to Cancel A Friend Request
cancelRequestButton.onClick.AddListener(() =>
{
//Make the Call to Reject the Friend Request using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().CancelFriendRequest(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to cancel a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Cancelled Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
}
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button unblockButton;
private PublicUserData _userData;
public void Create(PublicUserData userData)
{
...
//Setup the Button to Unblock a User
unblockButton.onClick.AddListener(() =>
{
//Make the Call to Unblock the given User using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().UnblockPlayer(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to unblock a player: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Unblocked a Player");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
...
}
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button addFriendButton;
private PublicUserData _userData;
public void Create(PublicUserData userData)
{
...
//Setup the Button to Request a Friend
addFriendButton.onClick.AddListener(() =>
{
//Make the call to initiate the Friend Request
AccelBytePlugin.GetLobby().RequestFriend(_userData.userId, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to send a friends request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Sent Friends Request");
//If we were successful, set the button to be non-intractable and change the Text
addFriendButton.interactable = false;
addFriendButton.GetComponentInChildren<Text>().text = "Request Sent";
}
});
});
...
}
private void CreateFriendUI(PublicUserData userData)
{
FriendStatusPanel panel = Instantiate(friendsDisplayPrefab, friendsDisplayPanel).GetComponent<FriendStatusPanel>();
panel.Create(userData);
if (!friendUIDictionary.ContainsKey(userData.userId))
{
friendUIDictionary.Add(userData.userId, panel);
}
// set up the any FriendStatusPanel's related button
panel.SetupButton();
}
/// Get Friends and Display them
private void GetFriends()
{
//Cleanup First LoopThroughTransformAndDestroy(friendsDisplayPanel.transform, friendsDisplayPlaceholder);
AccelBytePlugin.GetLobby().LoadFriendsList(result =>
{
//Check this is not an error
if (!result.IsError)
{
//Check if no friends were returned
if (result.Value.friendsId.Length <= 0)
{
//Display the Placeholder Text
friendsDisplayPlaceholder.gameObject.SetActive(true);
return;
}
//Hide the Placeholder Text
friendsDisplayPlaceholder.gameObject.SetActive(false);
//Fire off Requests to create UI for each friend
Debug.Log("Loaded Friends List Succesfully");
foreach (string friendID in result.Value.friendsId)
{
...
AccelBytePlugin.GetUser().GetUserByUserId(friendID, x =>
{
CreateFriendUI(x.Value);
});
}
}
else
{
//Display the Placeholder
friendsDisplayPlaceholder.gameObject.SetActive(true);
...
}
});
}
private void DisplayPending()
{
//Cleanup First, remove all Children from the Contents OTHER than the Placeholders
LoopThroughTransformAndDestroy(pendingIncomingRequestsContent.transform, pendingIncomingRequestPlaceholder);
LoopThroughTransformAndDestroy(pendingOutgoingRequestsContent.transform, pendingOutgoingRequestPlaceholder);
//Get all Incoming Friend Requests
AccelBytePlugin.GetLobby().ListIncomingFriends(result =>
{
//Check for an Error
if (result.IsError)
{
...
//Set the Placeholder Text to be Active so it doesn't just look broken
pendingIncomingRequestPlaceholder.gameObject.SetActive(true);
}
else
{
//If there are Zero Incoming Requests, set the PlaceHolder to be active
if (result.Value.friendsId.Length <= 0)
{
pendingIncomingRequestPlaceholder.gameObject.SetActive(true);
}
//Otherwise set the PlaceHolder to be inactive
else
{
pendingIncomingRequestPlaceholder.gameObject.SetActive(false);
}
//Loop through all the UserID's returned by the Friends callback and get their PublicUserData
foreach (string userID in result.Value.friendsId)
{
//Request the PublicUserData for the specific Friend
AccelBytePlugin.GetUser().GetUserByUserId(userID, userResult =>
{
if (userResult.IsError)
...
else
{
FriendsIncomingPanel incomingPanel = Instantiate(pendingIncomingRequestsPrefab, pendingIncomingRequestsContent).GetComponent<FriendsIncomingPanel>();
//Pass the PublicUserData into this function
incomingPanel.Create(userResult.Value);
}
});
}
}
});
AccelBytePlugin.GetLobby().ListOutgoingFriends(result =>
{
if (result.IsError)
...
else
{
if (result.Value.friendsId.Length <= 0)
{
pendingOutgoingRequestPlaceholder.gameObject.SetActive(true);
}
else
{
pendingOutgoingRequestPlaceholder.gameObject.SetActive(false);
}
foreach (string userID in result.Value.friendsId)
{
AccelBytePlugin.GetUser().GetUserByUserId(userID, userResult =>
{
if (userResult.IsError)
...
else
{
FriendsOutgoingPanel outgoingPanel = Instantiate(pendingOutgoingRequestsPrefab, pendingOutgoingRequestsContent).GetComponent<FriendsOutgoingPanel>();
outgoingPanel.Create(userResult.Value);
}
});
}
}
});
}
...
AccelBytePlugin.GetUser().GetUserByUserId(blockedUser.blockedUserId, userResult =>
{
...
if (userResult.IsError)
...
//If we have valid data, Instantiate the Prefab for the specific UI Piece and call relevant functions
else
{
FriendsBlockedPanel blockedPanel = Instantiate(blockedUserPrefab, blockedContent).GetComponent<FriendsBlockedPanel>();
//Pass the PublicUserData into this function
blockedPanel.Create(userResult.Value);
}
});
...
Congratulations! You have now fully implemented the Friends service.
Proceed to the next section to learn how to implement Party services (opens new window).
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using System.Collections.Generic;
using UnityEngine;
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine.Serialization;
using UnityEngine.UI;
using Button = UnityEngine.UI.Button;
public class FriendsManagementHandler : MonoBehaviour
{
private Dictionary<string, FriendStatusPanel> friendUIDictionary = new Dictionary<string, FriendStatusPanel>();
public GameObject FriendsManagementWindow;
[FormerlySerializedAs("FriendsPanel")]
[SerializeField]
private RectTransform friendsPanel;
[SerializeField]
private RectTransform requestsPanel;
[SerializeField]
private RectTransform blockedPanel;
#region Buttons
[SerializeField]
private Button friendsTabButton;
[SerializeField]
private Button pendingTabButton;
[SerializeField]
private Button blockedTabButton;
[SerializeField]
private Button exitButton;
#endregion
[SerializeField]
private Transform friendsDisplayPanel;
[FormerlySerializedAs("FriendsDisplayPrefab")]
[SerializeField]
private GameObject friendsDisplayPrefab;
[SerializeField]
private Button friendsSearchButton;
[SerializeField]
private Transform friendsDisplayPlaceholder;
[SerializeField]
private Transform blockedDisplayPlaceholder;
#region Search
[SerializeField]
private GameObject addFriendsPrefab;
[SerializeField]
private Transform friendsSearchPanel;
[SerializeField]
private InputField friendsSearchInputField;
[SerializeField]
private RectTransform friendsSearchScrollView;
[SerializeField]
private Button friendsSearchQuitButton;
[SerializeField]
private Transform friendsSearchPlaceholder;
#endregion
#region Pending
[SerializeField]
private RectTransform pendingIncomingRequestsContent;
[SerializeField]
private RectTransform pendingOutgoingRequestsContent;
[SerializeField]
private RectTransform blockedContent;
[SerializeField]
private GameObject pendingOutgoingRequestsPrefab;
[SerializeField]
private GameObject pendingIncomingRequestsPrefab;
[SerializeField]
private GameObject blockedUserPrefab;
[SerializeField]
private Transform pendingIncomingRequestPlaceholder;
[SerializeField]
private Transform pendingOutgoingRequestPlaceholder;
[SerializeField]
private Text pendingIncomingRequestText;
[SerializeField]
private Text pendingOutgoingRequestText;
#endregion
private bool setupStatus = false;
public enum FriendsMode
{
Default,
Friends,
Pending,
Blocked
};
private FriendsMode _displayMode = FriendsMode.Default;
private FriendsMode DisplayMode
{
get => _displayMode;
set
{
switch (value)
{
case FriendsMode.Default:
friendsPanel.gameObject.SetActive(true);
requestsPanel.gameObject.SetActive(false);
blockedPanel.gameObject.SetActive(false);
break;
case FriendsMode.Friends:
friendsPanel.gameObject.SetActive(true);
requestsPanel.gameObject.SetActive(false);
blockedPanel.gameObject.SetActive(false);
GetFriends();
break;
case FriendsMode.Pending:
requestsPanel.gameObject.SetActive(true);
friendsPanel.gameObject.SetActive(false);
blockedPanel.gameObject.SetActive(false);
DisplayPending();
break;
case FriendsMode.Blocked:
blockedPanel.gameObject.SetActive(true);
friendsPanel.gameObject.SetActive(false);
requestsPanel.gameObject.SetActive(false);
DisplayBlocked();
break;
}
}
}
public void UpdateFriends(FriendsStatusNotif notification)
{
//Find the friend and update it's UI
if (friendUIDictionary.ContainsKey(notification.userID))
{
friendUIDictionary[notification.userID].SetOnlineStatus(notification);
}
//Otherwise We should handle this in some way, possibly creating a Friend UI Piece
else
{
Debug.Log("Unregistered Friend received a Notification");
}
}
/// <summary>
/// Setup UI and prepare State
/// </summary>
/// <param name="exitType"> name of the destination panel</param>
public void Setup()
{
// reset the exit button's listener, then add the listener based on the exit screen type
exitButton.onClick.RemoveAllListeners();
exitButton.onClick.AddListener(() =>
{
FriendsManagementWindow.SetActive(false);
GetComponent<MenuHandler>().Menu.gameObject.SetActive(true);
});
// Check whether the FriendsPanel already set up or not
if (setupStatus)
{
DisplayMode = FriendsMode.Default;
return;
}
// Run the setup if it still hasn't
else
{
setupStatus = true;
DisplayMode = FriendsMode.Friends;
// reset listeners, so it won't triggered more than once
friendsTabButton.onClick.RemoveAllListeners();
pendingTabButton.onClick.RemoveAllListeners();
blockedTabButton.onClick.RemoveAllListeners();
// add the listeners
friendsTabButton.onClick.AddListener(() => DisplayMode = FriendsMode.Friends);
pendingTabButton.onClick.AddListener(() => DisplayMode = FriendsMode.Pending);
blockedTabButton.onClick.AddListener(() => DisplayMode = FriendsMode.Blocked);
friendsSearchPanel.gameObject.SetActive(false);
friendsDisplayPlaceholder.gameObject.SetActive(true);
friendsSearchQuitButton.onClick.AddListener(() => friendsSearchPanel.gameObject.SetActive(false));
friendsSearchButton.onClick.AddListener(DisplaySearch);
friendsSearchInputField.onEndEdit.AddListener(SearchForFriends);
friendsSearchButton.onClick.AddListener(() => friendsSearchPanel.gameObject.SetActive(true));
}
}
/// <summary>
/// Get Friends and Display them
/// </summary>
private void GetFriends()
{
//Cleanup First
LoopThroughTransformAndDestroy(friendsDisplayPanel.transform, friendsDisplayPlaceholder);
AccelBytePlugin.GetLobby().LoadFriendsList(result =>
{
//Check this is not an error
if (!result.IsError)
{
//Cleanup First
LoopThroughTransformAndDestroy(friendsDisplayPanel.transform, friendsDisplayPlaceholder);
//Check if no friends were returned
if (result.Value.friendsId.Length <= 0)
{
//Display the Placeholder Text
friendsDisplayPlaceholder.gameObject.SetActive(true);
return;
}
//Hide the Placeholder Text
friendsDisplayPlaceholder.gameObject.SetActive(false);
//Fire off Requests to create UI for each friend
Debug.Log("Loaded Friends List Succesfully");
foreach (string friendID in result.Value.friendsId)
{
Debug.Log($"Friend : {friendID}");
AccelBytePlugin.GetUser().GetUserByUserId(friendID, x =>
{
CreateFriendUI(x.Value);
});
}
}
else
{
//Display the Placeholder
friendsDisplayPlaceholder.gameObject.SetActive(true);
Debug.LogWarning("Error in Getting Friends");
}
});
}
private void CreateFriendUI(PublicUserData userData)
{
FriendStatusPanel panel = Instantiate(friendsDisplayPrefab, friendsDisplayPanel).GetComponent<FriendStatusPanel>();
panel.Create(userData);
if (!friendUIDictionary.ContainsKey(userData.userId))
{
friendUIDictionary.Add(userData.userId, panel);
}
panel.SetupButton();
}
private void DisplaySearch()
{
friendsSearchPanel.gameObject.SetActive(true);
LoopThroughTransformAndDestroy(friendsSearchScrollView.transform, friendsSearchPlaceholder);
friendsSearchPlaceholder.gameObject.SetActive(true);
}
private void SearchForFriends(string query)
{
AccelBytePlugin.GetUser().SearchUsers(query, result =>
{
if (!result.IsError)
{
ListQueriedusers(result.Value);
}
else
{
Debug.LogWarning($"Unable to Query Users Code: {result.Error.Code}, Message: {result.Error.Message}");
}
});
}
private void ListQueriedusers(PagedPublicUsersInfo pagedInfo)
{
//Cleanup First
LoopThroughTransformAndDestroy(friendsSearchScrollView.transform, friendsSearchPlaceholder);
if (pagedInfo.data.Length <=0)
{
friendsSearchPlaceholder.gameObject.SetActive(true);
}
else
{
friendsSearchPlaceholder.gameObject.SetActive(false);
foreach (PublicUserInfo info in pagedInfo.data)
{
FriendsAddPanel addPanel = Instantiate(addFriendsPrefab,friendsSearchScrollView).GetComponent<FriendsAddPanel>();
addPanel.Create(info);
}
}
}
private void DisplayPending()
{
//Cleanup First, remove all Children from the Contents OTHER than the Placeholders
LoopThroughTransformAndDestroy(pendingIncomingRequestsContent.transform, pendingIncomingRequestPlaceholder);
LoopThroughTransformAndDestroy(pendingOutgoingRequestsContent.transform, pendingOutgoingRequestPlaceholder);
//Get all Incoming Friend Requests
AccelBytePlugin.GetLobby().ListIncomingFriends(result =>
{
//Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Incoming Requests Code: {result.Error.Code}, Message: {result.Error.Message}");
//Set the Placeholder Text to be Active so it doesn't just look broken
pendingIncomingRequestPlaceholder.gameObject.SetActive(true);
}
else
{
//If there are Zero Incoming Requests, set the PlaceHolder to be active
if (result.Value.friendsId.Length <= 0)
{
pendingIncomingRequestPlaceholder.gameObject.SetActive(true);
}
//Otherwise set the PlaceHolder to be inactive
else
{
pendingIncomingRequestPlaceholder.gameObject.SetActive(false);
}
//Loop through all the UserID's returned by the Friends callback and get their PublicUserData
foreach (string userID in result.Value.friendsId)
{
//Request the PublicUserData for the specific Friend
AccelBytePlugin.GetUser().GetUserByUserId(userID, userResult =>
{
//If it's an Error, report it and do nothing else
if (userResult.IsError)
{
Debug.LogWarning($"Unable to User Code: {userResult.Error.Code}, Message: {userResult.Error.Message}");
}
//If we have valid data, Instantiate the Prefab for the specific UI Piece and call relevant functions
else
{
FriendsIncomingPanel incomingPanel = Instantiate(pendingIncomingRequestsPrefab, pendingIncomingRequestsContent).GetComponent<FriendsIncomingPanel>();
//Pass the PublicUserData into this function
incomingPanel.Create(userResult.Value);
}
});
}
}
});
AccelBytePlugin.GetLobby().ListOutgoingFriends(result =>
{
if (result.IsError)
{
Debug.LogWarning($"Unable to get Outgoing Requests Code: {result.Error.Code}, Message: {result.Error.Message}");
}
else
{
if (result.Value.friendsId.Length <= 0)
{
pendingOutgoingRequestPlaceholder.gameObject.SetActive(true);
}
else
{
pendingOutgoingRequestPlaceholder.gameObject.SetActive(false);
}
foreach (string userID in result.Value.friendsId)
{
AccelBytePlugin.GetUser().GetUserByUserId(userID, userResult =>
{
if (userResult.IsError)
{
Debug.LogWarning($"Unable to User Code: {userResult.Error.Code}, Message: {userResult.Error.Message}");
}
else
{
FriendsOutgoingPanel outgoingPanel = Instantiate(pendingOutgoingRequestsPrefab, pendingOutgoingRequestsContent).GetComponent<FriendsOutgoingPanel>();
outgoingPanel.Create(userResult.Value);
}
});
}
}
});
}
private void DisplayBlocked()
{
//Cleanup First
LoopThroughTransformAndDestroy(blockedContent.transform,blockedDisplayPlaceholder);
//Get Blocked List
AccelBytePlugin.GetLobby().GetListOfBlockedUser(result =>
{
//Check for an Error
if (result.IsError)
{
Debug.LogWarning($"Unable to get Blocked Player List Code: {result.Error.Code}, Message: {result.Error.Message}");
blockedDisplayPlaceholder.gameObject.SetActive(true);
}
else
{
blockedDisplayPlaceholder.gameObject.SetActive(false);
//Loop through all the UserID's returned by the callback and get their PublicUserData
foreach (BlockedData blockedUser in result.Value.data)
{
//Request the PublicUserData for the specific User
AccelBytePlugin.GetUser().GetUserByUserId(blockedUser.blockedUserId, userResult =>
{
//If it's an Error, report it and do nothing else
if (userResult.IsError)
{
Debug.LogWarning($"Unable to User Code: {userResult.Error.Code}, Message: {userResult.Error.Message}");
}
//If we have valid data, Instantiate the Prefab for the specific UI Piece and call relevant functions
else
{
FriendsBlockedPanel blockedPanel = Instantiate(blockedUserPrefab, blockedContent).GetComponent<FriendsBlockedPanel>();
//Pass the PublicUserData into this function
blockedPanel.Create(userResult.Value);
}
});
}
}
});
}
/// <summary>
/// A utility function to Destroy all Children of the parent transform. Optionally do not remove a specific Transform
/// </summary>
/// <param name="parent">Parent Object to destroy children</param>
/// <param name="doNotRemove">Optional specified Transform that should NOT be destroyed</param>
private static void LoopThroughTransformAndDestroy(Transform parent, Transform doNotRemove = null)
{
//Loop through all the children and add them to a List to then be deleted
List<GameObject> toBeDeleted = new List<GameObject>();
foreach (Transform t in parent)
{
//except the Do Not Remove transform if there is one
if (t != doNotRemove)
{
toBeDeleted.Add(t.gameObject);
}
}
//Loop through list and Delete all Children
for (int i = 0; i < toBeDeleted.Count; i++)
{
Destroy(toBeDeleted[i]);
}
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using System.Collections;
using System.Collections.Generic;
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
public class FriendStatusPanel : MonoBehaviour
{
[SerializeField]
private Image profilePicture;
[SerializeField]
private Image statusDisplay;
[SerializeField]
private Button chatButton;
[SerializeField]
private Button inviteToPartyButton;
[SerializeField]
private Button unfriendButton;
[SerializeField]
private Button blockButton;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Text onlineStatusText;
PublicUserData _userData;
void SetOnlineStatus(FriendsStatusNotif notification)
{
switch (notification.availability)
{
case "offline":
onlineStatusText.text = "Offline";
statusDisplay.color = Color.black;
break;
case "online":
onlineStatusText.text = "Online";
statusDisplay.color = Color.green;
break;
case "busy":
onlineStatusText.text = "Busy";
statusDisplay.color = Color.yellow;
break;
case "invisible":
onlineStatusText.text = "Offline";
statusDisplay.color = Color.black;
break;
default:
onlineStatusText.text = $"INVALID UNHANDLED {notification.availability}";
statusDisplay.color = Color.magenta;
break;
}
Debug.Log($"Friend Status for {notification.userID} changed to {notification.availability}");
}
public void Create(PublicUserData pud)
{
_userData = pud;
displayNameText.text = _userData.displayName;
}
public void UpdateUser(FriendsStatusNotif notification)
{
SetOnlineStatus(notification);
}
/// <summary>
/// Setup UI Button Listener
/// </summary>
public void SetupButton()
{
unfriendButton.onClick.AddListener(() =>
{
AccelBytePlugin.GetLobby().Unfriend(_userData.userId, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to unfriend a friend: code: {result.Error.Code}, message: {result.Error.Message}");
}
else
{
Debug.Log("Successfully unfriend a friend!");
LobbyHandler.Instance.GetComponent<FriendsManagementHandler>().RefreshFriendsList();
}
});
});
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
/// <summary>
/// Used to control the UI for the Incoming Pending Friend Request
/// </summary>
public class FriendsIncomingPanel : MonoBehaviour
{
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button acceptFriendButton;
[SerializeField]
private Button declineFriendButton;
[SerializeField]
private Button blockFriendButton;
private PublicUserData _userData;
/// <summary>
/// An initialisation Function required to be called to Populate the UI appropriately
/// </summary>
/// <param name="userData">The PublicUserData that is required to Populate the UI</param>
public void Create(PublicUserData userData)
{
//Cache the PublicUserData
_userData = userData;
//Set the Display Name
displayNameText.text = _userData.displayName;
//Setup the Button to Accept a Friend Request
acceptFriendButton.onClick.AddListener(() =>
{
//Make the Call to Accept the Friend Request using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().AcceptFriend(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to accept a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Accepted Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
//Setup the Button to Decline a Friend Request
declineFriendButton.onClick.AddListener(() =>
{
//Make the Call to Decline the Friend Request using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().RejectFriend(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to decline a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Declined Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
//Setup the Button to Block a Player
blockFriendButton.onClick.AddListener(() =>
{
//Make the Call to Block a Player using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().BlockPlayer(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to block a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Block Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
public class FriendsOutgoingPanel : MonoBehaviour
{
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button cancelRequestButton;
private PublicUserData _userData;
/// <summary>
/// An initialisation Function required to be called to Populate the UI appropriately
/// </summary>
/// <param name="userData">The PublicUserData that is required to Populate the UI</param>
public void Create(PublicUserData userData)
{
//Cache the PublicUserData
_userData = userData;
//Set the Display Name
displayNameText.text = _userData.displayName;
//Setup the Button to Cancel A Friend Request
cancelRequestButton.onClick.AddListener(() =>
{
//Make the Call to Reject the Friend Request using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().CancelFriendRequest(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to cancel a friend request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Cancelled Friend Request");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
public class FriendsBlockedPanel : MonoBehaviour
{
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button unblockButton;
private PublicUserData _userData;
/// <summary>
/// An initialisation Function required to be called to Populate the UI appropriately
/// </summary>
/// <param name="userData">The PublicUserData that is required to Populate the UI</param>
public void Create(PublicUserData userData)
{
//Cache the PublicUserData
_userData = userData;
//Set the Display Name
displayNameText.text = _userData.displayName;
//Setup the Button to Unblock a User
unblockButton.onClick.AddListener(() =>
{
//Make the Call to Unblock the given User using the cached PublicUserData UserID
AccelBytePlugin.GetLobby().UnblockPlayer(_userData.userId, result =>
{
if (result.IsError)
{
//We would probably want to display some user-feedback if the request is not successful
Debug.Log($"Failed to unblock a player: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Unblocked a Player");
//Destroy the UI Piece if the request was successful to remove it from the list
Destroy(gameObject);
}
});
});
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using AccelByte.Api;
using AccelByte.Models;
using UnityEngine;
using UnityEngine.UI;
using Image = UnityEngine.UI.Image;
/// <summary>
/// Controls the UI Piece associated with Adding a Friend from a Search
/// </summary>
public class FriendsAddPanel : MonoBehaviour
{
[SerializeField]
private Image profilePicture;
[SerializeField]
private Text displayNameText;
[SerializeField]
private Button addFriendButton;
private PublicUserInfo _userData;
/// <summary>
/// An initialisation Function required to be called to Populate the UI appropriately
/// </summary>
/// <param name="userInfo">The PublicUserInfo that is required to Populate the UI</param>
public void Create(PublicUserInfo userInfo)
{
//Cache the PublicUserInfo
_userData = userInfo;
//Set the Display Name
displayNameText.text = _userData.displayName;
//Setup the Button to Request a Friend
addFriendButton.onClick.AddListener(() =>
{
//Make the call to initiate the Friend Request
AccelBytePlugin.GetLobby().RequestFriend(_userData.userId, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to send a friends request: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
Debug.Log("Sent Friends Request");
//If we were successful, set the button to be non-intractable and change the Text
addFriendButton.interactable = false;
addFriendButton.GetComponentInChildren<Text>().text = "Request Sent";
}
});
});
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using UnityEngine;
using UnityEngine.UI;
public class MenuHandler : MonoBehaviour
{
public Transform Menu;
public Button FriendsButton;
private bool isInitialized = false;
public void Create()
{
if (isInitialized) return;
isInitialized = true;
FriendsButton.onClick.AddListener(() =>
{
GetComponent<FriendsManagementHandler>().Setup(FriendsManagementHandler.ExitMode.Menu);
Menu.gameObject.SetActive(false);
GetComponent<FriendsManagementHandler>().FriendsManagementWindow.SetActive(true);
});
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using UnityEngine;
using AccelByte.Api;
public class LobbyHandler : MonoBehaviour
{
/// <summary>
/// Private Instance
/// </summary>
static LobbyHandler _instance;
/// <summary>
/// The Instance Getter
/// </summary>
public static LobbyHandler Instance => _instance;
/// <summary>
/// The Instance Getter
/// </summary>
private Lobby _lobby;
[HideInInspector]
public NotificationHandler notificationHandler;
private void Awake()
{
// Check if another Instance is already created, and if so delete this one, otherwise destroy the object
if (_instance != null && _instance != this)
{
Destroy(this);
return;
}
else
{
_instance = this;
}
// Get the the object handler
notificationHandler = gameObject.GetComponent<NotificationHandler>();
}
/// <summary>
/// Connect to the <see cref="Lobby"/> and setup CallBacks
/// </summary>
public void ConnectToLobby()
{
//Get a reference to the instance of the Lobby
_lobby = AccelBytePlugin.GetLobby();
//Init menu handler
GetComponent<MenuHandler>().Create();
GetComponent<MenuHandler>().Menu.gameObject.SetActive(true);
//Connection
_lobby.Connected += notificationHandler.OnConnected;
_lobby.Disconnecting += notificationHandler.OnDisconnecting;
_lobby.Disconnected += notificationHandler.OnDisconnected;
//Friends
_lobby.FriendsStatusChanged += notificationHandler.OnFriendsStatusChanged;
_lobby.FriendRequestAccepted += notificationHandler.OnFriendRequestAccepted;
_lobby.OnIncomingFriendRequest += notificationHandler.OnIncomingFriendRequest;
_lobby.FriendRequestCanceled += notificationHandler.OnFriendRequestCanceled;
_lobby.FriendRequestRejected += notificationHandler.OnFriendRequestRejected;
_lobby.OnUnfriend += notificationHandler.OnUnfriend;
//Connect to the Lobby
if (!_lobby.IsConnected)
{
_lobby.Connect();
}
}
public void RemoveLobbyListeners()
{
//Remove delegate from Lobby
//Connection
_lobby.Connected -= notificationHandler.OnConnected;
_lobby.Disconnecting -= notificationHandler.OnDisconnecting;
_lobby.Disconnected -= notificationHandler.OnDisconnected;
//Friends
_lobby.FriendsStatusChanged -= notificationHandler.OnFriendsStatusChanged;
_lobby.FriendRequestAccepted -= notificationHandler.OnFriendRequestAccepted;
_lobby.OnIncomingFriendRequest -= notificationHandler.OnIncomingFriendRequest;
_lobby.FriendRequestCanceled -= notificationHandler.OnFriendRequestCanceled;
_lobby.FriendRequestRejected -= notificationHandler.OnFriendRequestRejected;
_lobby.OnUnfriend -= notificationHandler.OnUnfriend;
}
public void DisconnectFromLobby()
{
if (AccelBytePlugin.GetLobby().IsConnected)
{
AccelBytePlugin.GetLobby().Disconnect();
}
}
private void OnApplicationQuit()
{
// Attempt to Disconnect from the Lobby when the Game Quits
DisconnectFromLobby();
}
}
// Copyright (c) 2021 - 2022 AccelByte Inc. All Rights Reserved.
// This is licensed software from AccelByte Inc, for limitations
// and restrictions contact your company contract manager.
using UnityEngine;
using AccelByte.Models;
using AccelByte.Core;
public class NotificationHandler : MonoBehaviour
{
#region Notifications
// Collection of connection notifications
#region Connections
/// <summary>
/// Called when lobby is connected
/// </summary>
public void OnConnected()
{
Debug.Log("Lobby Connected");
}
/// <summary>
/// Called when connection is disconnecting
/// </summary>
/// <param name="result"> Contains data of message</param>
public void OnDisconnecting(Result<DisconnectNotif> result)
{
Debug.Log($"Lobby Disconnecting {result.Value.message}");
}
/// <summary>
/// Called when connection is being disconnected
/// </summary>
/// <param name="result"> Contains data of websocket close code</param>
public void OnDisconnected(WsCloseCode result)
{
Debug.Log($"Lobby Disconnected: {result}");
}
#endregion
// Collection of friend notifications
#region Friends
/// <summary>
/// Called when friend status is changed
/// </summary>
/// <param name="result"> Contains data of user id, availability, status, etc</param>
public void OnFriendsStatusChanged(Result<FriendsStatusNotif> result)
{
GetComponent<FriendsManagementHandler>().UpdateFriends(result.Value);
}
/// <summary>
/// Called when friend request is accepted
/// </summary>
/// <param name="result"> Contains data of friend's user id</param>
public void OnFriendRequestAccepted(Result<Friend> result)
{
Debug.Log($"Accepted a Friend Request from user {result.Value.friendId}");
}
/// <summary>
/// Called when there is incomming friend request
/// </summary>
/// <param name="result"> Contains data of friend's user id</param>
public void OnIncomingFriendRequest(Result<Friend> result)
{
Debug.Log($"Received a Friend Request from user {result.Value.friendId}");
}
/// <summary>
/// Called when friend is unfriend
/// </summary>
/// <param name="result"> Contains data of friend's user id</param>
public void OnUnfriend(Result<Friend> result)
{
Debug.Log($"Unfriended User {result.Value.friendId}");
}
/// <summary>
/// Called when friend request is canceled
/// </summary>
/// <param name="result"> Contains data of sender user id</param>
public void OnFriendRequestCanceled(Result<Acquaintance> result)
{
Debug.Log($"Cancelled a Friend Request from user {result.Value.userId}");
}
/// <summary>
/// Called when friend request is rejected
/// </summary>
/// <param name="result"> Contains data of rejector user id</param>
public void OnFriendRequestRejected(Result<Acquaintance> result)
{
Debug.Log($"Rejected a Friend Request from user {result.Value.userId}");
}
#endregion
#endregion
}