# Matchmaking Around Blocked Users

**URL:** https://heroiclabs.com/docs/nakama/guides/concepts/matchmaking-blocked-users/
**Summary:** A guide for implementing implementing Nakama's matchmaker to ensure players are not matched with any users they have blocked.
**Keywords:** matchmaker, blocked users, matchmaking, blocked, matchmaking criteria
**Categories:** nakama, matchmaking-blocked-users, concepts

---


# Matchmaking Around Blocked Users

Nakama's [matchmaker](../../../concepts/multiplayer/matchmaker/) can be used to bring users together for any type of social gameplay or interaction available in your application. As with any community, some users will get along and some will not.

When a user has [blocked](../../../concepts/friends/#block-a-friend) another, ideally these two users should not be placed in the same match, group, or other such social feature by the matchmaker.

This guide provides one approach you can use to ensure no user is matched with someone they have blocked. This involves:

* Looking up each user's list of blocked users
* Using that list as part of their respective [matchmaker properties](../../../concepts/multiplayer/matchmaker/#properties)
* Adding a clause to their matchmaker [query](../../../concepts/multiplayer/matchmaker/#query) to avoid matching blocked users

## Listing blocked users

Use the [Friends Listing API](../../../server-framework/typescript-runtime/function-reference/#friendsList), filtering only users in a blocked state, to get a complete list of all users this player has blocked.

{{< code type="client" >}}
```csharp
var blockedState = 3;
var blockedFriendsResult = await client.ListFriendsAsync(session, blockedState, 100, null);
```
{{< / code >}}

{{< code type="client" >}}
```swift
let blockedState = 3
let blockedFriendsResult = try client.listFriends(session: session, state: blockedState, limit: 100)
```
{{< / code >}}

{{< code type="client" >}}
```dart
const blockedState = FriendshipState.blocked;
final blockedFriendsResult = await client.listFriends(
  session: session,
  friendshipState: blockedState,
  limit: 100,
);
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const blockedState = 3;
const blockedFriendsResult = await client.listFriends(session, null, blockedState);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
int blockedState = 3;
auto successCallback = [](NFriendsPtr blockedFriendsResult)
{
  // Blocked friends available as blockedFriendsResult->friends
};

client->listFriends(session, {}, blockedState, {}, successCallback);
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var blocked_state = 3
var blocked_friends_result : NakamaAPI.ApiFriendList = yield(client.list_friends_async(session, blocked_state), "completed")
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var blocked_state = 3
var blocked_friends_result : NakamaAPI.ApiFriendList = await client.list_friends_async(session, blocked_state)
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
local limit = 100
local blocked_state = 3
local blocked_friends_result = client.list_friends(limit, blocked_state)
```
{{< / code >}}

{{< missing type="client" lang="java" />}}
{{< missing type="client" lang="shell" />}}
{{< missing type="client" lang="bash" />}}

You need to write the complete list of blocked user IDs into a space-separated string (e.g. `user-id-1 user-id-2 user-id-3`) that will be part of the user's matchmaker properties.

{{< code type="client" >}}
```csharp
var blockedFriendIds = string.Join(" ", blockedFriendsResult.Friends.Select(x => x.User.Id));
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const blockedFriendIds = blockedFriendsResult.friends.map(friend => friend.userId).join(' ');
```
{{< / code >}}

{{< code type="client" >}}
```swift
let blockedFriendIds = blockedFriendsResult.friends.map { $0.user.id }.joined(separator: " ")
```
{{< / code >}}

{{< code type="client" >}}
```dart
final blockedFriendIds = blockedFriendsResult.friends.map((friend) => friend.user.id).join(' ');
```
{{< / code >}}

{{< code type="client" >}}
```cpp
auto successCallback = [](NFriendListPtr blockedFriendsResult)
{
  string blockedFriendIds = "";
  for (NFriend friend : blockedFriendsResult->friends) {
    blockedFriendIdsString += friend.user.id + " ";
  }
};
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var blocked_friend_ids = ""

for friend in blocked_friends_result.friends:
  blocked_friend_ids += friend.user.id + " "
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var blocked_friend_ids = ""

for friend in blocked_friends_result.friends:
  blocked_friend_ids += friend.user.id + " "
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
local blocked_friend_ids = ""
for i,friend in ipairs(blocked_friends_result.friends) do
  blocked_friend_ids = blocked_friend_ids .. friend.user.id .. " "
end
```
{{< / code >}}

{{< missing type="client" lang="java" />}}
{{< missing type="client" lang="shell" />}}
{{< missing type="client" lang="bash" />}}

## Matchmaker criteria

Each user's matchmaker criteria will now include an additional property, using the key `blocked`, of the concatenated string of blocked users created above.

{{< code type="client" >}}
```csharp
var stringProperties = new Dictionary<string, string>
{
    { "blocked", blockedFriendIds }
}; 
```
{{< / code >}}

{{< code type="client" >}}
```swift
let stringProperties = ["blocked": blockedFriendIds]
```
{{< / code >}}

{{< code type="client" >}}
```dart
final stringProperties = {
  'blocked': blockedFriendIds,
};
```
{{< / code >}}

{{< code type="client" >}}
```javascript
const stringProperties = {
  "blocked": blockedFriendIds
};
```
{{< / code >}}

{{< code type="client" >}}
```cpp
NStringMap stringProperties;
stringProperties.emplace("blocked", blockedFriendIds);
```
{{< / code >}}

{{< code type="client" framework="godot3" >}}
```gdscript
var string_properties = { "blocked", blocked_friend_ids }
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var string_properties = { "blocked", blocked_friend_ids }
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
local string_properties = { blocked = blocked_friend_ids }
```
{{< / code >}}

{{< missing type="client" lang="java" />}}
{{< missing type="client" lang="shell" />}}
{{< missing type="client" lang="bash" />}}

Along with the new property, each user's matchmaker query will also have a new [`must not`](../../../concepts/multiplayer/query-syntax/#must-not) clause in the form `-properties.blocked:/.*my\-user\-id.*/`.

By using the player's own ID, this clause ensure that the searching player does not appear in the blocked list of any potential match - i.e. that this player is not matched with any player that has blocked them and, ultimately, no player is matched with anyone they have blocked.

The complete matchmaker request would look like:

{{< code type="client" >}}
```csharp
var blockedState = 3;
var blockedFriendsResult = await client.ListFriendsAsync(session, blockedState, 100, null);
var blockedFriendIds = string.Join(" ", blockedFriendsResult.Friends.Select(x => x.User.Id));]

var stringProperties = new Dictionary<string, string>
{
    { "blocked", blockedFriendIds }
};

var ticket =
    await socket.AddMatchmakerAsync($"-properties.blocked:/.*{session.UserId}.*/", 2, 4, stringProperties, null);
```
{{< /code >}}

{{< code type="client" >}}
```swift
let blockedState = 3
let blockedFriendsResult = try await client.listFriends(session: session, state: blockedState, limit: 100)

let blockedFriendIds = blockedFriendsResult.friends.map { $0.user.id }.joined(separator: " ")
let stringProperties = ["blocked": blockedFriendIds]

let ticket = try await socket.addMatchmaker(query: "-properties.blocked:/.*\(session.userId).*/", minCount: 2, maxCount: 4, stringProperties: stringProperties, numericProperties: nil)
```
{{< /code >}}

{{< code type="client" >}}
```dart
const blockedState = FriendshipState.blocked;

final blockedFriendsResult = await client.listFriends(
  session: session,
  friendshipState: blockedState,
  limit: 100,
);

final blockedFriendIds = blockedFriendsResult.friends.map((friend) => friend.user.id).join(' ');
final stringProperties = {
  'blocked': blockedFriendIds,
};

final ticket = await socket.addMatchmaker(
  query: "-properties.blocked:/.*${session.userId}.*/",
  minCount: 2,
  maxCount: 4,
  stringProperties: stringProperties,
  numericProperties: null,
);
```
{{< /code >}}

{{< code type="client" >}}
```javascript
const blockedState = 3;
const blockedFriendsResult = await client.listFriends(session, null, blockedState);
const blockedFriendIds = blockedFriendsResult.friends.map(friend => friend.userId).join(' ');

const stringProperties = {
  "blocked": blockedFriendIds
};

const ticket = await socket.addMatchmaker(`-properties.blocked:/.*${session.userId}.*/`, 2, 4, stringProperties, null);
```
{{< / code >}}

{{< code type="client" >}}
```cpp
int blockedState = 3;
auto successCallback = [](NFriendsPtr blockedFriendsResult)
{
  string blockedFriendIds = "";
  for (NFriend friend : blockedFriendsResult->friends) {
    blockedFriendIds += friend.user.id + " ";
  }

  NStringMap stringProperties;
  NStringDoubleMap numericProperties;
  stringProperties.emplace("blocked", blockedFriendIds);

  string query = "-properties.blocked:/.*" + blockedFriendIds + ".*/";
  rtClient->addMatchmaker(2, 4, query, stringProperties, numericProperties, matchmakerSuccessCallback);
};

client->listFriends(session, {}, blockedState, {}, successCallback);
```
{{< / code >}}


{{< code type="client" framework="godot3" >}}
```gdscript
var blocked_state = 3
var blocked_friends_result : NakamaAPI.ApiFriendList = yield(client.list_friends_async(session, blocked_state), "completed")
var blocked_friend_ids = ""

for friend in blocked_friends_result.friends:
  blocked_friend_ids += friend.user.id + " "

var string_properties = { "blocked", blocked_friend_ids }

var query = "-properties.blocked:/.*%s.*/" % [blocked_friend_ids]
var ticket : NakamaRTAPI.MatchmakerTicket = yield(socket.add_matchmaker_async(query, 2, 4, string_properties, null), "completed")
```
{{< / code >}}

{{< code type="client" framework="godot4" >}}
```gdscript
var blocked_state = 3
var blocked_friends_result : NakamaAPI.ApiFriendList = await client.list_friends_async(session, blocked_state)
var blocked_friend_ids = ""

for friend in blocked_friends_result.friends:
  blocked_friend_ids += friend.user.id + " "

var string_properties = { "blocked", blocked_friend_ids }

var query = "-properties.blocked:/.%s./" % [blocked_friend_ids]
var ticket : NakamaRTAPI.MatchmakerTicket = await socket.add_matchmaker_async(query, 2, 4, string_properties, null)
```
{{< / code >}}

{{< code type="client" framework="defold" >}}
```lua
local limit = 100
local blocked_state = 3
local blocked_friends_result = client.list_friends(limit, blocked_state)

local blocked_friend_ids = ""
for i,friend in ipairs(blocked_friends_result.friends) do
  blocked_friend_ids = blocked_friend_ids .. friend.user.id .. " "
end

local min_players = 2
local max_players = 4
local query = ("-properties.blocked:/.*%s.*/"):format(blocked_friend_ids)
local string_properties = { blocked = blocked_friend_ids}
local ticket = socket.matchmaker_add(min_players, max_players, query, string_properties)
```
{{< / code >}}

{{< missing type="client" lang="java" />}}
{{< missing type="client" lang="shell" />}}
{{< missing type="client" lang="bash" />}}
