Configure party settings
After adding the party logic and implementing the UI to your game, you can start configuring the settings of the Party service.
Follow these steps:
Inside
PartyHandler.cs
, add Unity Engine's UI library:using UnityEngine;
using UnityEngine.UI;Add references to your Party UI:
[SerializeField]
private GameObject LobbyWindow;
[SerializeField]
private Transform canvasTransform;
[SerializeField]
private Transform partyDisplayPanel;
[SerializeField]
private GameObject partyInvitationPrefab;
#region Buttons
[SerializeField]
private Button friendsManagementButton;
[SerializeField]
private Button createPartyButton;
[SerializeField]
private Button leavePartyButton;
[SerializeField]
private Button exitButton;
#endregion
[SerializeField]
private Text partyIdText;Create a new dictionary that will save your Party members' User IDs and display names.
public Dictionary<string, string> partyMembers { private set; get; }
Since
FriendsPanel
can be called from both the Menu and the Lobby, create a new enum for an exit mode. InFriendsManagementHandler.cs
, create a new enum with its getter and setter.#region ExitMode
public enum ExitMode
{
Menu,
Lobby
}
private ExitMode ExitScreen
{
get => ExitScreen;
set
{
switch (value)
{
case ExitMode.Menu:
FriendsManagementWindow.SetActive(false);
GetComponent<MenuHandler>().Menu.gameObject.SetActive(true);
break;
case ExitMode.Lobby:
FriendsManagementWindow.SetActive(false);
GetComponent<LobbyHandler>().LobbyWindow.SetActive(true);
break;
}
}
}
#endregionTo avoid setting up the listener twice, add a new boolean as a flag checker in
FriendsManagementHandler.cs
, and then change theSetup()
function:public void Setup(ExitMode exitType)
{
// Reset the exit button's listener, then add the listener based on the exit screen type
exitButton.onClick.RemoveAllListeners();
exitButton.onClick.AddListener(() =>
{
...
ExitScreen = exitType;
});
}Create a function in
PartyHandler.cs
to set up your Party UI when theLobbyPanel
is set to active./// Setup Party UI in Lobby and prepare state
public void SetupParty()
{
friendsManagementButton.onClick.AddListener(() =>
{
GetComponent<FriendsManagementHandler>().Setup(FriendsManagementHandler.ExitMode.Lobby);
LobbyWindow.SetActive(false);
GetComponent<FriendsManagementHandler>().FriendsManagementWindow.SetActive(true);
});
createPartyButton.onClick.AddListener(() => { CreateParty(); });
leavePartyButton.onClick.AddListener(() => { LeaveParty(); });
exitButton.onClick.AddListener(() =>
{
LobbyWindow.SetActive(false);
GetComponent<MenuHandler>().Menu.gameObject.SetActive(true);
});
}Before you continue with
PartyHandler.cs
, connect theLobbyPanel
with theMenuPanel
'sLobbyButton
. InMenuHandler.cs
, add a reference for theLobbyButton
.public Button LobbyButton;
Inside the
Create()
function, add theLobbyButton
's event listener and change theFriendsButton
'sSetup()
:public void Create()
{
LobbyButton.onClick.AddListener(() =>
{
GetComponent<PartyHandler>().SetupParty();
Menu.gameObject.SetActive(false);
GetComponent<LobbyHandler>().LobbyWindow.SetActive(true);
});
FriendsButton.onClick.AddListener(() =>
{
GetComponent<FriendsManagementHandler>().Setup(FriendsManagementHandler.ExitMode.Menu);
...
});
}In the Unity Editor, on the
MenuHandler.cs
script component in theAccelByteHandler
game object, drag the following objects to the appropriate variables.Go to
FriendStatusPanel.cs
and add aninviteToPartyButton
listener in theSetupButton()
function. Use theLobbyHandler
's instance to getPartyHandler
without needing to use the Find function.public void SetupButton()
{
inviteToPartyButton.onClick.AddListener(() =>
{
LobbyHandler.Instance.GetComponent<PartyHandler>().InviteToParty(_userData.userId);
});
...
}Update your
PartyInvitationPanel.cs
for when thePartyInvitationPopup
is spawned, such as in the following example:// Add some UI references
[SerializeField]
private GameObject invitationPopUp;
[SerializeField]
private Text invitationText;
[SerializeField]
private Button acceptInvitationButton;
[SerializeField]
private Button rejectInvitationButton;
// Create a function to setup the Popup and its listener
public void Setup(PartyInvitation partyInvitation)
{
AccelByteSDK.GetClientRegistry().GetApi().GetUser().GetUserByUserId(partyInvitation.from, result =>
{
invitationText.text = result.Value.displayName + " invite you to join their party\nAccept invitation?";
});
acceptInvitationButton.onClick.AddListener(() => { JoinParty(partyInvitation);});
rejectInvitationButton.onClick.AddListener(() => { RejectPartyInvitation(partyInvitation);});
}Add the following in
PartyInvitationPanel.cs
to destroy thePartyInvitationPopup
after the player accepts or rejects an invitation:public void JoinParty(PartyInvitation partyInvitation)
{
...
// Destroy the PopUp prefab
Destroy(invitationPopUp);
}
public void RejectPartyInvitation(PartyInvitation partyInvitation)
{
...
// Destroy the PopUp prefab
Destroy(invitationPopUp);
}In the Unity editor, open the
PartyInvitationPopup
prefab. Add thePartyInvitationPanels.cs
script as a component, then drag the objects to their exposed variables.In
PartyHandler.cs
, create a new function to Display Party data to thePartyListPanel
using theBulkGetUserInfo()
function to retrieve player data./// Display all Party Data to PartyList UI
public void DisplayPartyData(Result<PartyDataUpdateNotif> partyDataNotifResult)
{
// Update PartyID in UI
partyIdText.text = "PartyID: " + partyDataNotifResult.Value.partyId;
// Get all party members data based on _partyUserIds, then update data to UI
AccelByteSDK.GetClientRegistry().GetApi().GetUser().BulkGetUserInfo(partyDataNotifResult.Value.members, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to get party member's data: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
// Initialize dictionary
partyMembers = new Dictionary<string, string>();
// Result data's order => reversed order of _partyIserIds
int _index = result.Value.data.Length;
foreach (BaseUserInfo user in result.Value.data)
{
_index -= 1;
// Get transform of PlayerEntryDisplay, which is child of PartyListPanel
Transform playerEntryDisplay = partyDisplayPanel.GetChild(_index).transform;
if (user.userId == partyDataNotifResult.Value.leader)
{
// Set LeaderStatusIndicator as active
Transform leaderStatusIndicator = playerEntryDisplay.GetChild(0).transform;
leaderStatusIndicator.gameObject.SetActive(true);
}
else
{
if (AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId == partyDataNotifResult.Value.leader)
{
// Set PartyLeaderButton (promote button) as active, then add listener when onclick button
Transform partyLeaderButton = playerEntryDisplay.GetChild(1).transform;
partyLeaderButton.gameObject.SetActive(true);
partyLeaderButton.GetComponent<Button>().onClick.AddListener(() =>
{
PromotePartyLeader(user.userId);
});
// Set KickPartyButton as active, then add listener when onclick button
Transform kickPartyButton = playerEntryDisplay.GetChild(2).transform;
kickPartyButton.gameObject.SetActive(true);
kickPartyButton.GetComponent<Button>().onClick.AddListener(() =>
{
KickParty(user.userId);
});
}
}
// Set DisplayNameText as active, then change text to User's Display Name
Transform displayNameText = playerEntryDisplay.GetChild(3).transform;
displayNameText.gameObject.SetActive(true);
displayNameText.GetComponent<Text>().text = user.displayName;
partyMembers.Add(user.userId, user.displayName);
}
}
});
}You may want to display Party Member data if the Lobby is still connected. You can do this by adding the
Start()
function and then add Display Party data functionality usingGetPartyInfo()
.private void Start()
{
Lobby lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
if (lobby.IsConnected)
{
lobby.GetPartyInfo(partyInfoResult =>
{
// Update PartyID in the UI
partyIdText.text = "PartyID: " + partyInfoResult.Value.partyID;
ResetPlayerEntryUI();
// Get all party members data based on _partyUserIds, then update data in the UI
AccelByteSDK.GetClientRegistry().GetApi().GetUser().BulkGetUserInfo(partyInfoResult.Value.members, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to get party member's data: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
// Initialize dictionary
partyMembers = new Dictionary<string, string>();
// Result data's order => reversed order of _partyIserIds
int index = result.Value.data.Length;
foreach (BaseUserInfo user in result.Value.data)
{
index -= 1;
// Get transform of PlayerEntryDisplay, which is child of PartyListPanel
Transform playerEntryDisplay = partyDisplayPanel.GetChild(index).transform;
if (user.userId == partyInfoResult.Value.leaderID)
{
// Set LeaderStatusIndicator as active
Transform leaderStatusIndicator = playerEntryDisplay.GetChild(0).transform;
leaderStatusIndicator.gameObject.SetActive(true);
}
else
{
if (AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId == partyInfoResult.Value.leaderID)
{
// Set PartyLeaderButton (promote button) as active, then add listener when onclick button
Transform partyLeaderButton = playerEntryDisplay.GetChild(1).transform;
partyLeaderButton.gameObject.SetActive(true);
partyLeaderButton.GetComponent<Button>().onClick.AddListener(() =>
{
PromotePartyLeader(user.userId);
});
// Set KickPartyButton as active, then add listener when onclick button
Transform kickPartyButton = playerEntryDisplay.GetChild(2).transform;
kickPartyButton.gameObject.SetActive(true);
kickPartyButton.GetComponent<Button>().onClick.AddListener(() =>
{
KickParty(user.userId);
});
}
}
// Set DisplayNameText as active, then change text to User's Display Name
Transform displayNameText = playerEntryDisplay.GetChild(3).transform;
displayNameText.gameObject.SetActive(true);
displayNameText.GetComponent<Text>().text = user.displayName;
partyMembers.Add(user.userId, user.displayName);
}
}
});
});
}
}Prepare some Reset functions to reset the Party data and UI in
PartyHandler.cs
:/// Reset Party ID's UI
public void ResetPartyId()
{
partyIdText.text = "PartyID: ###############################";
partyMembers = null;
}
/// Reset Party List's UI
public void ResetPlayerEntryUI()
{
foreach(Transform playerEntryDisplay in partyDisplayPanel)
{
// Set LeaderStatusIndicator as not active
Transform leaderStatusIndicator = playerEntryDisplay.GetChild(0).transform;
leaderStatusIndicator.gameObject.SetActive(false);
// Set PartyLeaderButton (promote button) as not active, then remove all listener on button
Transform partyLeaderButton = playerEntryDisplay.GetChild(1).transform;
partyLeaderButton.gameObject.SetActive(false);
partyLeaderButton.GetComponent<Button>().onClick.RemoveAllListeners();
// Set KickPartyButton as not active, then remove all listener on button
Transform kickPartyButton = playerEntryDisplay.GetChild(2).transform;
kickPartyButton.gameObject.SetActive(false);
kickPartyButton.GetComponent<Button>().onClick.RemoveAllListeners();
// Set DisplayNameText as not active and set value to default text
Transform displayNameText = playerEntryDisplay.GetChild(3).transform;
displayNameText.gameObject.SetActive(false);
displayNameText.GetComponent<Text>().text = "PlayerUsername";
}
}The Party UI must be reset when a player leaves their current party, when displaying data, or on a player's first connection to the Lobby. To do this, call the Reset function in
PartyHandler.cs
:public void LeaveParty()
{
ResultCallback leavePartyCallback = result =>
{
if (result.IsError)
{
...
}
else
{
...
// Reset all Party-related UIs
ResetPartyId();
ResetPlayerEntryUI();
}
};
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().LeaveParty(leavePartyCallback);
}
public void DisplayPartyData(Result<PartyDataUpdateNotif> partyDataNotifResult)
{
// Udate PartyID in UI
...
// Reset the Party List's UI
ResetPlayerEntryUI();
...
}You will need the notification display to appear in the notification box. To do this, create a new script called
LogMessagePanel.cs
and attach it to theLogMessageDisplay
prefab. Once completed, add the following to the script:using UnityEngine;
using UnityEngine.UI;
public class LogMessagePanel : MonoBehaviour
{
[SerializeField]
private Text messageText;
/// Update Notification Message's UI
public void UpdateNotificationUI(string text, Color color)
{
messageText.text = text;
messageText.color = color;
}
}In
LobbyHandler.cs
, add the following UI references:public GameObject LobbyWindow;
#region Notification Box
[Header("Notification Box")]
[SerializeField]
private Transform notificationBoxContentView;
[SerializeField]
private GameObject logMessagePrefab;
#endregionAdd the following function in
LobbyHandler.cs
. This function will be called to instantiate the log message in the notification box./// Write the log message on the notification box
public void WriteLogMessage(string text, Color color)
{
LogMessagePanel logPanel = Instantiate(logMessagePrefab, notificationBoxContentView).GetComponent<LogMessagePanel>();
logPanel.UpdateNotificationUI(text, color);
}In the Unity Editor, on your
AccelByteHandler
, drag the following objects to the exposed variables.In
PartyHandler.cs
, create functions to handle each update event inLobbyHandler.cs
and to create notification messages./// Called on update when a party invitation is received
public void InvitePartyNotification(PartyInvitation partyInvitation)
{
Debug.Log($"Invited by: {partyInvitation.from}");
PartyInvitationPanel invitationPanel = Instantiate(partyInvitationPrefab, canvasTransform).GetComponent<PartyInvitationPanel>();
invitationPanel.Setup(partyInvitation);
}
/// Called on update when kicked from party
public void KickPartyNotification()
{
Debug.Log("You're kicked from party");
ResetPartyId();
ResetPlayerEntryUI();
}
/// Called on update when a friend joins the party
public void JoinedPartyNotification(JoinNotification joinNotification)
{
Debug.Log("Invitee join a party");
AccelByteSDK.GetClientRegistry().GetApi().GetUser().GetUserByUserId(joinNotification.userID, result =>
{
if (result.IsError)
{
Debug.Log($"Failed to get user data: error code: {result.Error.Code} message: {result.Error.Message}");
}
else
{
LobbyHandler.Instance.WriteLogMessage($"[Party] {result.Value.displayName} join the party", Color.black);
}
});
}
/// Called on update when a friend leaves the party
public void LeavePartyNotification(LeaveNotification leaveNotification)
{
if (leaveNotification.userID != AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId)
{
Debug.Log($"{leaveNotification.userID} leave the party");
LobbyHandler.Instance.WriteLogMessage($"[Party] {partyMembers[leaveNotification.userID]} leave the party", Color.black);
}
}While still in
PartyHandler.cs
, add the following code under thePromotePartyLeader()
function to notify players whether their Promote Party Leader action succeeds or fails.public void PromotePartyLeader(string memberUserId)
{
// Instantiate the notification message
NotificationMessagePanel notificationPanel = Instantiate(notificationMessagePrefab, notificationContentView).GetComponent<NotificationMessagePanel>();
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().PromotePartyLeader(memberUserId, result =>
{
if (result.IsError)
{
...
// Update the messageText that failed to promote leader
LobbyHandler.Instance.WriteLogMessage($"[Party] Failed to promote {partyMembers[memberUserId]} to be party leader", Color.black);
}
else
{
...
// Update the messageText that success to promote leader
LobbyHandler.Instance.WriteLogMessage($"[Party] Successfully promote {partyMembers[memberUserId]} to be party leader", Color.black);
}
});
}Create new functions in
NotificationHandler.cs
that will be called from the notifications events when there is an update.// Collection of party notifications
#region Party
/// Called when user gets party invitation
public void OnInvitedToParty(Result<PartyInvitation> result)
{
GetComponent<PartyHandler>().InvitePartyNotification(result.Value);
}
/// Called when user joins the party
public void OnJoinedParty(Result<JoinNotification> result)
{
GetComponent<PartyHandler>().JoinedPartyNotification(result.Value);
}
/// Called when user is kicked by party leader
public void OnKickedFromParty(Result<KickNotification> result)
{
GetComponent<PartyHandler>().KickPartyNotification();
}
/// Called when user leaves the party
public void OnLeaveFromParty(Result<LeaveNotification> result)
{
GetComponent<PartyHandler>().LeavePartyNotification(result.Value);
}
/// Called when user rejects party invitation
public void OnRejectedPartyInvitation(Result<PartyRejectNotif> result)
{
Debug.Log("[Party-Notification] Invitee rejected a party invitation");
}
/// Called when party data is updated
public void OnPartyDataUpdateNotif(Result<PartyDataUpdateNotif> result)
{
GetComponent<PartyHandler>().DisplayPartyData(result);
}
#endregionChange your notification update events in
LobbyHandler.cs
under theConnectToLobby()
function, such as in the following example:public void ConnectToLobby()
{
...
// Party
lobby.InvitedToParty += notificationHandler.OnInvitedToParty;
lobby.JoinedParty += notificationHandler.OnJoinedParty;
lobby.KickedFromParty += notificationHandler.OnKickedFromParty;
lobby.LeaveFromParty += notificationHandler.OnLeaveFromParty;
lobby.RejectedPartyInvitation += notificationHandler.OnRejectedPartyInvitation;
lobby.PartyDataUpdateNotif += notificationHandler.OnPartyDataUpdateNotif;
...
}Update the
RemoveLobbyListeners()
function inLobbyHandler.cs
to reset the notification update events, such as in the following example:public void RemoveLobbyListeners()
{
...
// Party
lobby.InvitedToParty -= notificationHandler.OnInvitedToParty;
lobby.JoinedParty -= notificationHandler.OnJoinedParty;
lobby.KickedFromParty -= notificationHandler.OnKickedFromParty;
lobby.LeaveFromParty -= notificationHandler.OnLeaveFromParty;
lobby.RejectedPartyInvitation -= notificationHandler.OnRejectedPartyInvitation;
lobby.PartyDataUpdateNotif -= notificationHandler.OnPartyDataUpdateNotif;
}Save and return to the Unity Editor. In your scene, on the
AccelByteHandler
gameObject, drag the appropriate objects into the exposed variables of thePartyHandler
script component.
What's next?
Congratulations! You have now fully implemented the Party service.