diff --git a/docs/discord-social-sdk/development-guides/creating-a-unified-friends-list.mdx b/docs/discord-social-sdk/development-guides/creating-a-unified-friends-list.mdx index 3f6435e58d..2b95ae6957 100644 --- a/docs/discord-social-sdk/development-guides/creating-a-unified-friends-list.mdx +++ b/docs/discord-social-sdk/development-guides/creating-a-unified-friends-list.mdx @@ -25,13 +25,18 @@ Before you begin, make sure you have: ### Implementing a Unified Friends List -The Discord friend list is ultimately constructed from two entities: Relationships, and Users. You can query Relationships API to find everyone a user is a friend with, and the Users API to find the necessary extra information for rendering the list, such as whether they are online or not. +The Discord friend list is ultimately constructed from two entities: Relationships, and Users. You can query +Relationships API to find everyone a user is a friend with, and the Users API to find the necessary extra information +for rendering the list, such as whether they are online or not. ### Relationships -[Relationships](/docs/discord-social-sdk/development-guides/managing-relationships) are how Discord models friends, friend requests, and more. All relationships for the current user are loaded when the Client connects. Each relationship has a target user id, and a type, such as `Friend`, `PendingOutgoing`, or `Blocked`. The set of all relationships can be queried with [`Client::GetRelationships`]. +[Relationships](/docs/discord-social-sdk/development-guides/managing-relationships) are how Discord models friends, +friend requests, and more. All relationships for the current user are loaded when the Client connects. Each +relationship has a target user id, and a type, such as `Friend`, `PendingOutgoing`, or `Blocked`. -To allow users to manage their relationships in your game, you should provide a way to accept or reject friend requests, block users, and manage pending requests. See [Development Guide: Managing Relationships in Your Game](/docs/discord-social-sdk/development-guides/managing-relationships) for implementation details. +To allow users to manage their relationships in your game, you should provide a way to accept or reject friend +requests, block users, and manage pending requests. See [Development Guide: Managing Relationships in Your Game](/docs/discord-social-sdk/development-guides/managing-relationships) for implementation details. ### Users @@ -50,13 +55,144 @@ The SDK will only display activities associated with the current game, meaning y See our [Design Guidelines: Status & Rich Presence](/docs/discord-social-sdk/design-guidelines/status-rich-presence) for best practices on displaying presence information. -Let's combine to create a unified friends list. +There are two ways in which you can create a unified friends list in your game: + +1. Using the SDK Unified Friends List helper functions, which automatically group and sort +relationships and users for you. +2. Directly retrieving relationships and users from the SDK, and sorting manually. + +## Approach 1: Using SDK Unified Friends List Helper Functions + +:::info +This approach is recommended as it significantly reduces the amount of code you need to write and maintain compared to +manually fetching and organizing relationships, while ensuring your friends list follows Discord's best practices. +::: + +The Discord Social SDK provides built-in helper functions that automatically group and sort your friends list according +to Discord's [recommended design guidelines](/docs/discord-social-sdk/design-guidelines/unified-friends-list). +This approach is generally simpler and more maintainable than manually fetching and organizing relationships. + +The SDK automatically organizes friends into the three groups we find via [`RelationshipGroupType`]: +- `OnlinePlayingGame`: Friends who are online and currently playing your game +- `OnlineElsewhere`: Friends who are online but not playing your game +- `Offline`: Friends who are offline + +### Step 1: Display the Unified Friends List + +The [`Client::GetRelationshipsByGroup`] method returns a pre-sorted list of relationships for a specific group type. +This eliminates the need to manually filter, categorize, and sort friends yourself. The SDK handles all the logic +for determining which group each friend belongs to based on their online status and game activity, and +automatically sorts users within each group (for example, users who have played your game are moved to the top of +the OnlineElsewhere group). + +Let's create a function that uses the SDK helper functions to display a properly organized friends list: + +```cpp +void DisplayUnifiedFriendsList(const std::shared_ptr &client) { + // Get friends playing the game + const auto onlineInGame = client->GetRelationshipsByGroup( + discordpp::RelationshipGroupType::OnlinePlayingGame + ); + + // Get friends online elsewhere + const auto onlineElsewhere = client->GetRelationshipsByGroup( + discordpp::RelationshipGroupType::OnlineElsewhere + ); + + // Get offline friends + const auto offline = client->GetRelationshipsByGroup( + discordpp::RelationshipGroupType::Offline + ); + + // Display "Online - GameTitle" Friends + std::cout << "\n=== Online - GameTitle (" << onlineInGame.size() << ") ===\n"; + for (const auto& relationship : onlineInGame) { + auto user = relationship.User(); + if (user) { + std::string displayStr = "🟣 " + user->DisplayName(); + + // Add Discord friend indicator + if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) { + displayStr += " 👾"; + } + + // Add game friend indicator + if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) { + displayStr += " 🎮"; + } + + std::cout << displayStr << "\n"; + } + } + + // Display "Online - Elsewhere" Friends + std::cout << "\n=== Online - Elsewhere (" << onlineElsewhere.size() << ") ===\n"; + for (const auto& relationship : onlineElsewhere) { + auto user = relationship.User(); + if (user) { + std::string displayStr = "🟢 " + user->DisplayName(); + + // Add Discord friend indicator + if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) { + displayStr += " 👾"; + } + + // Add game friend indicator + if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) { + displayStr += " 🎮"; + } + + std::cout << displayStr << "\n"; + } + } + + // Display "Offline" Friends + std::cout << "\n=== Offline (" << offline.size() << ") ===\n"; + for (const auto& relationship : offline) { + auto user = relationship.User(); + if (user) { + std::string displayStr = "⚫ " + user->DisplayName(); + + // Add Discord friend indicator + if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) { + displayStr += " 👾"; + } + + // Add game friend indicator + if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) { + displayStr += " 🎮"; + } + + std::cout << displayStr << "\n"; + } + } +} +``` + +### Step 2: Set Up Automatic Updates + +To keep your friends list up-to-date automatically, use the [`Client::SetRelationshipGroupsUpdatedCallback`]. This +callback is triggered whenever any change occurs that might affect the friends list grouping, such as a friend going +online or offline, or when a relationship changes, such as when you accept a friend request, or block a user. + +```cpp +// Set up the unified friends list update callback +client->SetRelationshipGroupsUpdatedCallback([&client](const uint64_t userId) { + std::cout << "👥 Friends list updated for user: " << userId << std::endl; + DisplayUnifiedFriendsList(client); +}); +``` --- -## Step 1: Fetch Relationships +## Approach 2: Manually Fetching Relationships and Users + +In this section we'll show a more manual method which gives you more control over how the friends list is displayed in your game. + +### Step 1: Fetch Relationships -First, let's create a function to see what kind of relationships and information we have to work with: +First, let's create a function that utilises [`Client::GetRelationships`] to query all the relationships and +user information we for our account: ```cpp void DisplayFriendsList(discordpp::Client& client) { @@ -122,7 +258,7 @@ This will output the raw relationship data to the console. You can use this info --- -## Step 2: Organize Relationships +### Step 2: Organize Relationships Based on our design guidelines for a [Unified Friends List](/docs/discord-social-sdk/design-guidelines/unified-friends-list), you should separate the player's friends list into three sections: `Online - GameTitle`, `Online - Elsewhere`, and `Offline`. @@ -219,7 +355,7 @@ void DisplayFriendsList(std::shared_ptr client) { If we build and run our application, we should now see a list of friends separated into three categories: `Online - GameTitle`, `Online - Elsewhere`, and `Offline`. -## Step 3: Monitor Changes to Users +### Step 3: Monitor Changes to Users To monitor for user changes, we're going using the [`Client::SetUserUpdatedCallback`] function. @@ -242,7 +378,7 @@ user list, or similar operations. ::: --- -## Step 4: Monitor Changes in Relationships +### Step 4: Monitor Changes in Relationships Let us setup two callbacks to handle relationship updates. @@ -251,7 +387,7 @@ These examples rebuild the friends list from scratch every time a relationship c recommend maintaining a collection of [`UserHandle`] objects and adding and removing them appropriately. ::: -### Relationship Created Callback +#### Relationship Created Callback This can happen when a user sends or accepts a friend invite, or blocks a user. @@ -266,7 +402,7 @@ client->SetRelationshipCreatedCallback([&client](uint64_t userId, bool isDiscord }); ``` -### Relationship Deleted Callback +#### Relationship Deleted Callback This can happen when a user rejects a friend request or removes a friend. @@ -303,11 +439,15 @@ Now that you have a unified friends list, you can build on your social features ## Change Log -| Date | Changes | -|----------------|-----------------| -| March 17, 2025 | Initial release | +| Date | Changes | +|----------------|------------------------| +| March 17, 2025 | Initial release | +| July 17, 2025 | Add UFL helper methods | {/* Autogenerated Reference Links */} [`Client::GetRelationships`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ad481849835cd570f0e03adafcf90125d +[`Client::GetRelationshipsByGroup`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a9f7898d3f3d1ec92b06c662df70746d5 +[`Client::SetRelationshipGroupsUpdatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#af12441ef091298f968075b7190851098 [`Client::SetUserUpdatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a3559f375165acedc6d6677ef599b3a4a +[`RelationshipGroupType`]: https://discord.com/developers/docs/social-sdk/namespacediscordpp.html#a503ed2f7b0bfbd435321a0e8b1dfba35 [`UserHandle`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1UserHandle.html#a587bcc838e42dc5c56f840a350070707 \ No newline at end of file