M Core/NosSmooth.Game/Data/Chat/Friend.cs => Core/NosSmooth.Game/Data/Chat/Friend.cs +4 -12
  
@@ 4,24 4,16 @@
 //  Copyright (c) František Boháček. All rights reserved.
 //  Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
+using NosSmooth.Packets.Enums.Relations;
+
 namespace NosSmooth.Game.Data.Chat;
 
 /// <summary>
 /// Represents character's friend.
 /// </summary>
-public class Friend
+public record Friend(long PlayerId, CharacterRelationType RelationType)
 {
     /// <summary>
-    /// The id of the character.
-    /// </summary>
-    public long CharacterId { get; internal set; }
-
-    // <summary>
-    // The type of the relation.
-    // </summary>
-    // public CharacterRelationType RelationType { get; internal set; }
-
-    /// <summary>
     /// The name of the character.
     /// </summary>
     public string? CharacterName { get; internal set; }
@@ 29,5 21,5 @@ public class Friend
     /// <summary>
     /// Whether the friend is connected to the server.
     /// </summary>
-    public bool IsOnline { get; internal set; }
+    public bool IsConnected { get; internal set; }
 }=
\ No newline at end of file
 
M Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs => Core/NosSmooth.Game/Extensions/ServiceCollectionExtensions.cs +1 -0
  
@@ 42,6 42,7 @@ public static class ServiceCollectionExtensions
             .AddPacketResponder<PlayerSkillResponder>()
             .AddPacketResponder<WalkResponder>()
             .AddPacketResponder<SkillUsedResponder>()
+            .AddPacketResponder<FriendInitResponder>()
             .AddPacketResponder<InventoryInitResponder>()
             .AddPacketResponder<GroupInitResponder>()
             .AddPacketResponder<AoeSkillUsedResponder>()
 
M Core/NosSmooth.Game/Game.cs => Core/NosSmooth.Game/Game.cs +28 -0
  
@@ 189,6 189,34 @@ public class Game : IStatefulEntity
     }
 
     /// <summary>
+    /// Creates the friends if it is null, or updates the current friends.
+    /// </summary>
+    /// <param name="create">The function for creating the friends.</param>
+    /// <param name="update">The function for updating the friends.</param>
+    /// <param name="releaseSemaphore">Whether to release the semaphore used for changing the friends.</param>
+    /// <param name="ct">The cancellation token for cancelling the operation.</param>
+    /// <returns>The updated friends.</returns>
+    internal async Task<IReadOnlyList<Friend>?> CreateOrUpdateFriendsAsync
+    (
+        Func<IReadOnlyList<Friend>?> create,
+        Func<IReadOnlyList<Friend>, IReadOnlyList<Friend>?> update,
+        bool releaseSemaphore = true,
+        CancellationToken ct = default
+    )
+    {
+        return await CreateOrUpdateAsync
+        (
+            GameSemaphoreType.Friends,
+            () => Friends,
+            c => Friends = c,
+            create,
+            update,
+            releaseSemaphore,
+            ct
+        );
+    }
+
+    /// <summary>
     /// Creates the group if it is null, or updates the current group.
     /// </summary>
     /// <param name="create">The function for creating the group.</param>
 
A Core/NosSmooth.Game/PacketHandlers/Relations/FriendInitResponder.cs => Core/NosSmooth.Game/PacketHandlers/Relations/FriendInitResponder.cs +83 -0
  
@@ 0,0 1,83 @@
+//
+//  FriendInitResponder.cs
+//
+//  Copyright (c) František Boháček. All rights reserved.
+//  Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using NosSmooth.Core.Packets;
+using NosSmooth.Game.Data.Chat;
+using NosSmooth.Packets.Enums.Relations;
+using NosSmooth.Packets.Server.Relations;
+using Remora.Results;
+
+namespace NosSmooth.Game.PacketHandlers.Relations;
+
+/// <summary>
+/// A friends initialization responder.
+/// </summary>
+public class FriendInitResponder : IPacketResponder<FInfoPacket>, IPacketResponder<FInitPacket>
+{
+    private readonly Game _game;
+
+    /// <summary>
+    /// Initializes a new instance of the <see cref="FriendInitResponder"/> class.
+    /// </summary>
+    /// <param name="game">The game.</param>
+    public FriendInitResponder(Game game)
+    {
+        _game = game;
+    }
+
+    /// <inheritdoc />
+    public async Task<Result> Respond(PacketEventArgs<FInfoPacket> packetArgs, CancellationToken ct = default)
+    {
+        var packet = packetArgs.Packet;
+
+        await _game.CreateOrUpdateFriendsAsync
+        (
+            () => null,
+            friends => friends
+                .Select(
+                    x =>
+                    {
+                        if (x.PlayerId == packet.PlayerId)
+                        {
+                            x.IsConnected = packet.IsConnected;
+                            x.CharacterName = packet.Name;
+                        }
+
+                        return x;
+                    })
+                .ToList(),
+            ct: ct
+        );
+
+        return Result.FromSuccess();
+    }
+
+    /// <inheritdoc />
+    public async Task<Result> Respond(PacketEventArgs<FInitPacket> packetArgs, CancellationToken ct = default)
+    {
+        var packet = packetArgs.Packet;
+        var friends = packet.FriendSubPackets
+            .Select
+            (
+                x => new Friend(x.PlayerId, x.RelationType ?? CharacterRelationType.Blocked)
+                {
+                    PlayerId = x.PlayerId,
+                    CharacterName = x.Name,
+                    IsConnected = x.IsConnected
+                }
+            )
+            .ToList();
+
+        await _game.CreateOrUpdateFriendsAsync
+        (
+            () => friends,
+            _ => friends,
+            ct: ct
+        );
+
+        return Result.FromSuccess();
+    }
+}<
\ No newline at end of file