public void GroupTest()
        {
            // login, create character, start game
            FakeNetworkClient clientA = HandlerTestHelper.InitializeTestEnvironment();
            FakeNetworkClient clientB = HandlerTestHelper.CreateFakeNetworkClient();

            Thread.Sleep(1000);

            // client A asks client B for group
            PJoinPacket pjoinPacketRequest = new PJoinPacket()
            {
                CharacterId = clientB.Session.Character.CharacterId,
                RequestType = GroupRequestType.Invited
            };

            clientA.ReceivePacket(pjoinPacketRequest);
            HandlerTestHelper.WaitForPackets(clientA, 1);

            // client B accepts group request
            PJoinPacket pjoinPacketAccept = new PJoinPacket()
            {
                CharacterId = clientA.Session.Character.CharacterId,
                RequestType = GroupRequestType.Accepted
            };

            clientB.ReceivePacket(pjoinPacketAccept);
            HandlerTestHelper.WaitForPackets(clientA, 1);

            // check if group has been created successfully
            Assert.IsNotNull(clientA.Session.Character.Group);
            Assert.IsNotNull(clientB.Session.Character.Group);
            Assert.AreEqual(2, clientA.Session.Character.Group.CharacterCount);
        }
        protected override async Task Handle(GroupInvitationSendEvent e, CancellationToken cancellation)
        {
            if (!(e.Sender is IPlayerEntity player))
            {
                return;
            }

            IPlayerEntity sender = _playerManager.GetPlayerByCharacterId(e.Sender.Id);
            IPlayerEntity target = _playerManager.GetPlayerByCharacterId(e.Target.Character.Id);

            if (target == null || sender == null)
            {
                return;
            }

            _groupManager.CreateInvitation(sender, target);

            await player.SendChatMessageAsync(PlayerMessages.GROUP_PLAYER_X_INVITED_TO_YOUR_GROUP, SayColorType.Yellow);

            PacketBase acceptPacket = new PJoinPacket {
                CharacterId = target.Id, RequestType = PJoinPacketType.Accepted
            };
            PacketBase refusePacket = new PJoinPacket {
                CharacterId = target.Id, RequestType = PJoinPacketType.Declined
            };
            string question = target.GetLanguageFormat(PlayerMessages.GROUP_PLAYER_X_INVITED_YOU_TO_JOIN_HIS_GROUP, sender.Character.Name);
            await target.SendDialog(acceptPacket, refusePacket, question);
        }
        /// <summary>
        /// pjoin packet
        /// </summary>
        /// <param name="pjoinPacket"></param>
        public void GroupJoin(PJoinPacket pjoinPacket)
        {
            bool          createNewGroup = true;
            ClientSession targetSession  = ServerManager.Instance.GetSessionByCharacterId(pjoinPacket.CharacterId);

            if (targetSession == null && !pjoinPacket.RequestType.Equals(GroupRequestType.Sharing))
            {
                return;
            }

            switch (pjoinPacket.RequestType)
            {
            case GroupRequestType.Requested:
            case GroupRequestType.Invited:
                if (pjoinPacket.CharacterId == 0)
                {
                    return;
                }
                if (ServerManager.Instance.IsCharactersGroupFull(pjoinPacket.CharacterId))
                {
                    Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("GROUP_FULL")));
                    return;
                }

                if (ServerManager.Instance.IsCharacterMemberOfGroup(pjoinPacket.CharacterId) && ServerManager.Instance.IsCharacterMemberOfGroup(Session.Character.CharacterId))
                {
                    Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("ALREADY_IN_GROUP")));
                    return;
                }

                if (Session.Character.CharacterId == pjoinPacket.CharacterId)
                {
                    return;
                }
                if (targetSession == null)
                {
                    return;
                }
                if (Session.Character.IsBlockedByCharacter(pjoinPacket.CharacterId))
                {
                    Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("BLACKLIST_BLOCKED")));
                    return;
                }

                if (targetSession.Character.GroupRequestBlocked)
                {
                    Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("GROUP_BLOCKED"), 0));
                }
                else
                {
                    // save sent group request to current character
                    Session.Character.GroupSentRequestCharacterIds.Add(targetSession.Character.CharacterId);
                    if (Session.Character.Group == null || Session.Character.Group.GroupType == GroupType.Group)
                    {
                        if (targetSession.Character?.Group == null || targetSession.Character?.Group.GroupType == GroupType.Group)
                        {
                            Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(string.Format(Language.Instance.GetMessageFromKey("GROUP_REQUEST"), targetSession.Character.Name)));
                            targetSession.SendPacket(UserInterfaceHelper.Instance.GenerateDialog($"#pjoin^3^{ Session.Character.CharacterId} #pjoin^4^{Session.Character.CharacterId} {string.Format(Language.Instance.GetMessageFromKey("INVITED_YOU"), Session.Character.Name)}"));
                        }
                        else
                        {
                            Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(string.Format(Language.Instance.GetMessageFromKey("GROUP_CANT_INVITE"), targetSession.Character.Name)));
                        }
                    }
                    else
                    {
                        targetSession.SendPacket($"qna #rd^1^{Session.Character.CharacterId}^1 {string.Format(Language.Instance.GetMessageFromKey("INVITED_YOU_RAID"), Session.Character.Name)}");
                    }
                }
                break;

            case GroupRequestType.Sharing:
                if (Session.Character.Group == null)
                {
                    return;
                }
                Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("GROUP_SHARE_INFO")));
                Session.Character.Group.Characters.Where(s => s.Character.CharacterId != Session.Character.CharacterId).ToList().ForEach(s =>
                {
                    s.SendPacket(UserInterfaceHelper.Instance.GenerateDialog($"#pjoin^6^{ Session.Character.CharacterId} #pjoin^7^{Session.Character.CharacterId} {string.Format(Language.Instance.GetMessageFromKey("INVITED_YOU_SHARE"), Session.Character.Name)}"));
                    Session.Character.GroupSentRequestCharacterIds.Add(s.Character.CharacterId);
                });
                break;

            case GroupRequestType.Accepted:
                if (targetSession != null && !targetSession.Character.GroupSentRequestCharacterIds.Contains(Session.Character.CharacterId))
                {
                    return;
                }
                if (targetSession != null)
                {
                    if (targetSession.Character.GroupSentRequestCharacterIds.Count <= 0)
                    {
                        return;
                    }
                    if (Session.Character.CharacterId <= 0)
                    {
                        return;
                    }
                    targetSession.Character.GroupSentRequestCharacterIds.Remove(Session.Character.CharacterId);

                    if (ServerManager.Instance.IsCharacterMemberOfGroup(Session.Character.CharacterId) && ServerManager.Instance.IsCharacterMemberOfGroup(pjoinPacket.CharacterId))
                    {
                        // everyone is in group, return
                        return;
                    }

                    if (ServerManager.Instance.IsCharactersGroupFull(pjoinPacket.CharacterId) || ServerManager.Instance.IsCharactersGroupFull(Session.Character.CharacterId))
                    {
                        Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("GROUP_FULL")));
                        targetSession.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("GROUP_FULL")));
                        return;
                    }


                    // get group and add to group
                    if (ServerManager.Instance.IsCharacterMemberOfGroup(Session.Character.CharacterId))
                    {
                        // target joins source
                        Group currentGroup = ServerManager.Instance.GetGroupByCharacterId(Session.Character.CharacterId);

                        if (currentGroup != null)
                        {
                            currentGroup.JoinGroup(targetSession);
                            targetSession.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("JOINED_GROUP")));
                            createNewGroup = false;
                        }
                    }
                    else if (ServerManager.Instance.IsCharacterMemberOfGroup(pjoinPacket.CharacterId))
                    {
                        // source joins target
                        Group currentGroup = ServerManager.Instance.GetGroupByCharacterId(pjoinPacket.CharacterId);

                        if (currentGroup != null)
                        {
                            createNewGroup = false;
                            if (currentGroup.GroupType == GroupType.Group)
                            {
                                currentGroup.JoinGroup(Session);
                            }
                            else
                            {
                                Session.SendPacket(Session.Character.GenerateSay(string.Format(Language.Instance.GetMessageFromKey("RAID_JOIN"), Session.Character.Name), 10));
                                if (Session.Character.Level > currentGroup.Raid?.LevelMaximum || Session.Character.Level < currentGroup.Raid?.LevelMinimum)
                                {
                                    Session.SendPacket(Session.Character.GenerateSay(Language.Instance.GetMessageFromKey("RAID_LEVEL_INCORRECT"), 10));
                                    if (Session.Character.Level >= currentGroup.Raid?.LevelMaximum + 10 /* && AlreadySuccededToday*/)
                                    {
                                        //modal 1 ALREADY_SUCCEDED_AS_ASSISTANT
                                    }
                                }

                                currentGroup.JoinGroup(Session);
                                Session.SendPacket(Session.Character.GenerateRaid(1, false));
                                currentGroup.Characters.ToList().ForEach(s =>
                                {
                                    s.SendPacket(currentGroup.GenerateRdlst());
                                    s.SendPacket(s.Character.GenerateSay(string.Format(Language.Instance.GetMessageFromKey("JOIN_TEAM"), Session.Character.Name), 10));
                                    s.SendPacket(s.Character.GenerateRaid(0, false));
                                    if (!currentGroup.IsLeader(s))
                                    {
                                        s.SendPacket(s.Character.GenerateRaid(2, false));
                                    }
                                });
                            }
                        }
                    }


                    if (createNewGroup)
                    {
                        var group = new Group(GroupType.Group);
                        group.JoinGroup(pjoinPacket.CharacterId);
                        Session.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(string.Format(Language.Instance.GetMessageFromKey("GROUP_JOIN"), targetSession.Character.Name)));
                        group.JoinGroup(Session.Character.CharacterId);
                        ServerManager.Instance.AddGroup(group);
                        targetSession.SendPacket(UserInterfaceHelper.Instance.GenerateInfo(Language.Instance.GetMessageFromKey("GROUP_ADMIN")));

                        // set back reference to group
                        Session.Character.Group       = group;
                        targetSession.Character.Group = group;
                    }
                }
                if (Session?.Character?.Group.GroupType != GroupType.Group)
                {
                    return;
                }
                // player join group
                ServerManager.Instance.UpdateGroup(pjoinPacket.CharacterId);
                Session.CurrentMapInstance?.Broadcast(Session.Character.GeneratePidx());
                break;

            default:
                switch (pjoinPacket.RequestType)
                {
                case GroupRequestType.Declined:
                    if (targetSession != null && !targetSession.Character.GroupSentRequestCharacterIds.Contains(Session.Character.CharacterId))
                    {
                        return;
                    }
                    if (targetSession != null)
                    {
                        targetSession.Character.GroupSentRequestCharacterIds.Remove(Session.Character.CharacterId);

                        targetSession.SendPacket(Session.Character.GenerateSay(string.Format(Language.Instance.GetMessageFromKey("REFUSED_GROUP_REQUEST"), Session.Character.Name), 10));
                    }
                    break;

                case GroupRequestType.AcceptedShare:
                    if (targetSession != null && !targetSession.Character.GroupSentRequestCharacterIds.Contains(Session.Character.CharacterId))
                    {
                        return;
                    }
                    if (targetSession != null)
                    {
                        if (Session?.Character.Group == null)
                        {
                            return;
                        }
                        targetSession.Character.GroupSentRequestCharacterIds.Remove(Session.Character.CharacterId);

                        Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(string.Format(Language.Instance.GetMessageFromKey("ACCEPTED_SHARE"), targetSession.Character.Name), 0));
                        if (Session.Character.Group.IsMemberOfGroup(pjoinPacket.CharacterId))
                        {
                            Session.Character.SetReturnPoint(targetSession.Character.Return.DefaultMapId, targetSession.Character.Return.DefaultX, targetSession.Character.Return.DefaultY);
                            targetSession.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(string.Format(Language.Instance.GetMessageFromKey("CHANGED_SHARE"), targetSession.Character.Name), 0));
                        }
                    }
                    break;

                case GroupRequestType.DeclinedShare:
                    if (targetSession != null && !targetSession.Character.GroupSentRequestCharacterIds.Contains(Session.Character.CharacterId))
                    {
                        return;
                    }
                    targetSession?.Character.GroupSentRequestCharacterIds.Remove(Session.Character.CharacterId);

                    Session.SendPacket(UserInterfaceHelper.Instance.GenerateMsg(Language.Instance.GetMessageFromKey("REFUSED_SHARE"), 0));
                    break;

                case GroupRequestType.Requested:
                    break;

                case GroupRequestType.Invited:
                    break;

                case GroupRequestType.Accepted:
                    break;

                case GroupRequestType.Sharing:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
                break;
            }
        }