Пример #1
0
        void HandleAddFriend(AddFriend packet)
        {
            if (!ObjectManager.NormalizePlayerName(ref packet.Name))
            {
                return;
            }

            FriendsResult friendResult = FriendsResult.NotFound;
            ObjectGuid    friendGuid   = Global.CharacterCacheStorage.GetCharacterGuidByName(packet.Name);

            if (!friendGuid.IsEmpty())
            {
                CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(friendGuid);
                if (characterInfo != null)
                {
                    Team team            = Player.TeamForRace(characterInfo.RaceId);
                    uint friendAccountId = characterInfo.AccountId;

                    if (HasPermission(RBACPermissions.AllowGmFriend) || Global.AccountMgr.IsPlayerAccount(Global.AccountMgr.GetSecurity(friendAccountId, (int)Global.WorldMgr.GetRealm().Id.Realm)))
                    {
                        if (friendGuid == GetPlayer().GetGUID())
                        {
                            friendResult = FriendsResult.Self;
                        }
                        else if (GetPlayer().GetTeam() != team && !HasPermission(RBACPermissions.TwoSideAddFriend))
                        {
                            friendResult = FriendsResult.Enemy;
                        }
                        else if (GetPlayer().GetSocial().HasFriend(friendGuid))
                        {
                            friendResult = FriendsResult.Already;
                        }
                        else
                        {
                            Player playerFriend = Global.ObjAccessor.FindPlayer(friendGuid);
                            if (playerFriend && playerFriend.IsVisibleGloballyFor(GetPlayer()))
                            {
                                friendResult = FriendsResult.AddedOnline;
                            }
                            else
                            {
                                friendResult = FriendsResult.AddedOffline;
                            }

                            if (GetPlayer().GetSocial().AddToSocialList(friendGuid, SocialFlag.Friend))
                            {
                                GetPlayer().GetSocial().SetFriendNote(friendGuid, packet.Notes);
                            }
                            else
                            {
                                friendResult = FriendsResult.ListFull;
                            }
                        }
                    }
                }
            }

            Global.SocialMgr.SendFriendStatus(GetPlayer(), friendResult, friendGuid);
        }
Пример #2
0
        public ChannelOwnerAppend(Channel channel, ObjectGuid ownerGuid)
        {
            _channel   = channel;
            _ownerGuid = ownerGuid;
            _ownerName = "";

            CharacterCacheEntry characterCacheEntry = Global.CharacterCacheStorage.GetCharacterCacheByGuid(_ownerGuid);

            if (characterCacheEntry != null)
            {
                _ownerName = characterCacheEntry.Name;
            }
        }
Пример #3
0
        public bool Initialize(ObjectGuid guid, Player player = null)
        {
            CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid);

            if (characterInfo == null)
            {
                return(false);
            }

            if (player)
            {
                Cypher.Assert(player.GetGUID() == guid);

                AccountID     = player.GetSession().GetAccountGUID();
                BnetAccountID = player.GetSession().GetBattlenetAccountGUID();
                Name          = player.GetName();
                RaceID        = player.GetRace();
                Sex           = player.GetNativeSex();
                ClassID       = player.GetClass();
                Level         = (byte)player.GetLevel();

                DeclinedName names = player.GetDeclinedNames();
                if (names != null)
                {
                    DeclinedNames = names;
                }
            }
            else
            {
                uint accountId     = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(guid);
                uint bnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(accountId);

                AccountID     = ObjectGuid.Create(HighGuid.WowAccount, accountId);
                BnetAccountID = ObjectGuid.Create(HighGuid.BNetAccount, bnetAccountId);
                Name          = characterInfo.Name;
                RaceID        = characterInfo.RaceId;
                Sex           = characterInfo.Sex;
                ClassID       = characterInfo.ClassId;
                Level         = characterInfo.Level;
            }

            IsDeleted           = characterInfo.IsDeleted;
            GuidActual          = guid;
            VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress();

            return(true);
        }
Пример #4
0
        void HandleGuildFinderGetRecruits(LFGuildGetRecruits lfGuildGetRecruits)
        {
            Player player = GetPlayer();
            Guild  guild  = player.GetGuild();

            if (!guild)
            {
                return;
            }

            long            now             = Time.UnixTime;
            LFGuildRecruits lfGuildRecruits = new LFGuildRecruits();

            lfGuildRecruits.UpdateTime = now;
            var recruitsList = Global.GuildFinderMgr.GetAllMembershipRequestsForGuild(guild.GetGUID());

            if (recruitsList != null)
            {
                foreach (var recruitRequestPair in recruitsList)
                {
                    LFGuildRecruitData recruitData = new LFGuildRecruitData();
                    recruitData.RecruitGUID            = recruitRequestPair.Key;
                    recruitData.RecruitVirtualRealm    = Global.WorldMgr.GetVirtualRealmAddress();
                    recruitData.Comment                = recruitRequestPair.Value.GetComment();
                    recruitData.ClassRoles             = recruitRequestPair.Value.GetClassRoles();
                    recruitData.PlayStyle              = recruitRequestPair.Value.GetInterests();
                    recruitData.Availability           = recruitRequestPair.Value.GetAvailability();
                    recruitData.SecondsSinceCreated    = (uint)(now - recruitRequestPair.Value.GetSubmitTime());
                    recruitData.SecondsUntilExpiration = (uint)(recruitRequestPair.Value.GetExpiryTime() - now);

                    CharacterCacheEntry charInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(recruitRequestPair.Key);
                    if (charInfo != null)
                    {
                        recruitData.Name            = charInfo.Name;
                        recruitData.CharacterClass  = (byte)charInfo.ClassId;
                        recruitData.CharacterGender = (byte)charInfo.Sex;
                        recruitData.CharacterLevel  = charInfo.Level;
                    }

                    lfGuildRecruits.Recruits.Add(recruitData);
                }
            }

            player.SendPacket(lfGuildRecruits);
        }
Пример #5
0
        public static void LeaveAllArenaTeams(ObjectGuid guid)
        {
            CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid);

            if (characterInfo == null)
            {
                return;
            }

            for (byte i = 0; i < SharedConst.MaxArenaSlot; ++i)
            {
                uint arenaTeamId = characterInfo.ArenaTeamId[i];
                if (arenaTeamId != 0)
                {
                    ArenaTeam arenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(arenaTeamId);
                    if (arenaTeam != null)
                    {
                        arenaTeam.DelMember(guid, true);
                    }
                }
            }
        }
Пример #6
0
        void HandleAddIgnore(AddIgnore packet)
        {
            if (!ObjectManager.NormalizePlayerName(ref packet.Name))
            {
                return;
            }

            ObjectGuid    ignoreGuid;
            FriendsResult ignoreResult = FriendsResult.IgnoreNotFound;

            CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByName(packet.Name);

            if (characterInfo != null)
            {
                ignoreGuid = characterInfo.Guid;
                ObjectGuid ignoreAccountGuid = ObjectGuid.Create(HighGuid.WowAccount, characterInfo.AccountId);
                if (ignoreGuid == GetPlayer().GetGUID())              //not add yourself
                {
                    ignoreResult = FriendsResult.IgnoreSelf;
                }
                else if (GetPlayer().GetSocial().HasIgnore(ignoreGuid, ignoreAccountGuid))
                {
                    ignoreResult = FriendsResult.IgnoreAlready;
                }
                else
                {
                    ignoreResult = FriendsResult.IgnoreAdded;

                    // ignore list full
                    if (!GetPlayer().GetSocial().AddToSocialList(ignoreGuid, ignoreAccountGuid, SocialFlag.Ignored))
                    {
                        ignoreResult = FriendsResult.IgnoreFull;
                    }
                }
            }

            Global.SocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, ObjectGuid.Empty);
        }
Пример #7
0
        void HandleCalendarInvite(CalendarInvitePkt calendarInvite)
        {
            ObjectGuid playerGuid = GetPlayer().GetGUID();

            ObjectGuid inviteeGuid    = ObjectGuid.Empty;
            Team       inviteeTeam    = 0;
            ulong      inviteeGuildId = 0;

            if (!ObjectManager.NormalizePlayerName(ref calendarInvite.Name))
            {
                return;
            }

            Player player = Global.ObjAccessor.FindPlayerByName(calendarInvite.Name);

            if (player)
            {
                // Invitee is online
                inviteeGuid    = player.GetGUID();
                inviteeTeam    = player.GetTeam();
                inviteeGuildId = player.GetGuildId();
            }
            else
            {
                // Invitee offline, get data from database
                ObjectGuid guid = Global.CharacterCacheStorage.GetCharacterGuidByName(calendarInvite.Name);
                if (!guid.IsEmpty())
                {
                    CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid);
                    if (characterInfo != null)
                    {
                        inviteeGuid    = guid;
                        inviteeTeam    = Player.TeamForRace(characterInfo.RaceId);
                        inviteeGuildId = characterInfo.GuildId;
                    }
                }
            }

            if (inviteeGuid.IsEmpty())
            {
                Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.PlayerNotFound);
                return;
            }

            if (GetPlayer().GetTeam() != inviteeTeam && !WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionCalendar))
            {
                Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NotAllied);
                return;
            }

            SQLResult result1 = DB.Characters.Query("SELECT flags FROM character_social WHERE guid = {0} AND friend = {1}", inviteeGuid, playerGuid);

            if (!result1.IsEmpty())
            {
                if (Convert.ToBoolean(result1.Read <byte>(0) & (byte)SocialFlag.Ignored))
                {
                    Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.IgnoringYouS, calendarInvite.Name);
                    return;
                }
            }

            if (!calendarInvite.Creating)
            {
                CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarInvite.EventID);
                if (calendarEvent != null)
                {
                    if (calendarEvent.IsGuildEvent() && calendarEvent.GuildId == inviteeGuildId)
                    {
                        // we can't invite guild members to guild events
                        Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NoGuildInvites);
                        return;
                    }

                    CalendarInvite invite = new(Global.CalendarMgr.GetFreeInviteId(), calendarInvite.EventID, inviteeGuid, playerGuid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.Invited, CalendarModerationRank.Player, "");
                    Global.CalendarMgr.AddInvite(calendarEvent, invite);
                }
                else
                {
                    Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.EventInvalid);
                }
            }
            else
            {
                if (calendarInvite.IsSignUp && inviteeGuildId == GetPlayer().GetGuildId())
                {
                    Global.CalendarMgr.SendCalendarCommandResult(playerGuid, CalendarError.NoGuildInvites);
                    return;
                }

                CalendarInvite invite = new(calendarInvite.EventID, 0, inviteeGuid, playerGuid, SharedConst.CalendarDefaultResponseTime, CalendarInviteStatus.Invited, CalendarModerationRank.Player, "");
                Global.CalendarMgr.SendCalendarEventInvite(invite);
            }
        }
Пример #8
0
        static bool HandleCharacterChangeAccountCommand(StringArguments args, CommandHandler handler)
        {
            string playerNameStr;
            string accountName;

            handler.ExtractOptFirstArg(args, out playerNameStr, out accountName);
            if (accountName.IsEmpty())
            {
                return(false);
            }

            ObjectGuid targetGuid;
            string     targetName;

            if (!handler.ExtractPlayerTarget(new StringArguments(playerNameStr), out _, out targetGuid, out targetName))
            {
                return(false);
            }

            CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(targetGuid);

            if (characterInfo == null)
            {
                handler.SendSysMessage(CypherStrings.PlayerNotFound);
                return(false);
            }

            uint oldAccountId = characterInfo.AccountId;
            uint newAccountId = oldAccountId;

            PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_ID_BY_NAME);

            stmt.AddValue(0, accountName);
            SQLResult result = DB.Login.Query(stmt);

            if (!result.IsEmpty())
            {
                newAccountId = result.Read <uint>(0);
            }
            else
            {
                handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
                return(false);
            }

            // nothing to do :)
            if (newAccountId == oldAccountId)
            {
                return(true);
            }

            uint charCount = Global.AccountMgr.GetCharactersCount(newAccountId);

            if (charCount != 0)
            {
                if (charCount >= WorldConfig.GetIntValue(WorldCfg.CharactersPerRealm))
                {
                    handler.SendSysMessage(CypherStrings.AccountCharacterListFull, accountName, newAccountId);
                    return(false);
                }
            }

            stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ACCOUNT_BY_GUID);
            stmt.AddValue(0, newAccountId);
            stmt.AddValue(1, targetGuid.GetCounter());
            DB.Characters.DirectExecute(stmt);

            Global.WorldMgr.UpdateRealmCharCount(oldAccountId);
            Global.WorldMgr.UpdateRealmCharCount(newAccountId);

            Global.CharacterCacheStorage.UpdateCharacterAccountId(targetGuid, newAccountId);

            handler.SendSysMessage(CypherStrings.ChangeAccountSuccess, targetName, accountName);

            string       logString = $"changed ownership of player {targetName} ({targetGuid}) from account {oldAccountId} to account {newAccountId}";
            WorldSession session   = handler.GetSession();

            if (session != null)
            {
                Player player = session.GetPlayer();
                if (player != null)
                {
                    Log.outCommand(session.GetAccountId(), $"GM {player.GetName()} (Account: {session.GetAccountId()}) {logString}");
                }
            }
            else
            {
                Log.outCommand(0, $"{handler.GetCypherString(CypherStrings.Console)} {logString}");
            }
            return(true);
        }
Пример #9
0
        void HandleSendMail(SendMail packet)
        {
            if (packet.Info.Attachments.Count > SharedConst.MaxMailItems)                      // client limit
            {
                GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.TooManyAttachments);
                return;
            }

            if (!CanOpenMailBox(packet.Info.Mailbox))
            {
                return;
            }

            if (string.IsNullOrEmpty(packet.Info.Target))
            {
                return;
            }

            Player player = GetPlayer();

            if (player.getLevel() < WorldConfig.GetIntValue(WorldCfg.MailLevelReq))
            {
                SendNotification(CypherStrings.MailSenderReq, WorldConfig.GetIntValue(WorldCfg.MailLevelReq));
                return;
            }

            ObjectGuid receiverGuid = ObjectGuid.Empty;

            if (ObjectManager.NormalizePlayerName(ref packet.Info.Target))
            {
                receiverGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(packet.Info.Target);
            }

            if (receiverGuid.IsEmpty())
            {
                Log.outInfo(LogFilter.Network, "Player {0} is sending mail to {1} (GUID: not existed!) with subject {2}" +
                            "and body {3} includes {4} items, {5} copper and {6} COD copper with StationeryID = {7}",
                            GetPlayerInfo(), packet.Info.Target, packet.Info.Subject, packet.Info.Body,
                            packet.Info.Attachments.Count, packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID);
                player.SendMailResult(0, MailResponseType.Send, MailResponseResult.RecipientNotFound);
                return;
            }

            if (packet.Info.SendMoney < 0)
            {
                GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.InternalError);
                Log.outWarn(LogFilter.Server, "Player {0} attempted to send mail to {1} ({2}) with negative money value (SendMoney: {3})",
                            GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.SendMoney);
                return;
            }

            if (packet.Info.Cod < 0)
            {
                GetPlayer().SendMailResult(0, MailResponseType.Send, MailResponseResult.InternalError);
                Log.outWarn(LogFilter.Server, "Player {0} attempted to send mail to {1} ({2}) with negative COD value (Cod: {3})",
                            GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.Cod);
                return;
            }

            Log.outInfo(LogFilter.Network, "Player {0} is sending mail to {1} ({2}) with subject {3} and body {4}" +
                        "includes {5} items, {6} copper and {7} COD copper with StationeryID = {8}",
                        GetPlayerInfo(), packet.Info.Target, receiverGuid.ToString(), packet.Info.Subject,
                        packet.Info.Body, packet.Info.Attachments.Count, packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID);

            if (player.GetGUID() == receiverGuid)
            {
                player.SendMailResult(0, MailResponseType.Send, MailResponseResult.CannotSendToSelf);
                return;
            }

            uint cost = (uint)(!packet.Info.Attachments.Empty() ? 30 * packet.Info.Attachments.Count : 30);  // price hardcoded in client

            long reqmoney = cost + packet.Info.SendMoney;

            // Check for overflow
            if (reqmoney < packet.Info.SendMoney)
            {
                player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotEnoughMoney);
                return;
            }

            if (!player.HasEnoughMoney(reqmoney) && !player.IsGameMaster())
            {
                player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotEnoughMoney);
                return;
            }

            Player receiver = Global.ObjAccessor.FindPlayer(receiverGuid);

            Team receiverTeam          = 0;
            byte mailsCount            = 0;                       //do not allow to send to one player more than 100 mails
            byte receiverLevel         = 0;
            uint receiverAccountId     = 0;
            uint receiverBnetAccountId = 0;

            if (receiver)
            {
                receiverTeam          = receiver.GetTeam();
                mailsCount            = (byte)receiver.GetMails().Count;
                receiverLevel         = (byte)receiver.getLevel();
                receiverAccountId     = receiver.GetSession().GetAccountId();
                receiverBnetAccountId = receiver.GetSession().GetBattlenetAccountId();
            }
            else
            {
                CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(receiverGuid);
                if (characterInfo != null)
                {
                    receiverTeam      = Player.TeamForRace(characterInfo.RaceId);
                    receiverLevel     = characterInfo.Level;
                    receiverAccountId = characterInfo.AccountId;
                }

                PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_COUNT);
                stmt.AddValue(0, receiverGuid.GetCounter());

                SQLResult result = DB.Characters.Query(stmt);
                if (!result.IsEmpty())
                {
                    mailsCount = (byte)result.Read <ulong>(0);
                }

                receiverBnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(receiverAccountId);
            }

            // do not allow to have more than 100 mails in mailbox.. mails count is in opcode byte!!! - so max can be 255..
            if (mailsCount > 100)
            {
                player.SendMailResult(0, MailResponseType.Send, MailResponseResult.RecipientCapReached);
                return;
            }

            // test the receiver's Faction... or all items are account bound
            bool accountBound = !packet.Info.Attachments.Empty();

            foreach (var att in packet.Info.Attachments)
            {
                Item item = player.GetItemByGuid(att.ItemGUID);
                if (item)
                {
                    ItemTemplate itemProto = item.GetTemplate();
                    if (itemProto == null || !itemProto.GetFlags().HasAnyFlag(ItemFlags.IsBoundToAccount))
                    {
                        accountBound = false;
                        break;
                    }
                }
            }

            if (!accountBound && player.GetTeam() != receiverTeam && !HasPermission(RBACPermissions.TwoSideInteractionMail))
            {
                player.SendMailResult(0, MailResponseType.Send, MailResponseResult.NotYourTeam);
                return;
            }

            if (receiverLevel < WorldConfig.GetIntValue(WorldCfg.MailLevelReq))
            {
                SendNotification(CypherStrings.MailReceiverReq, WorldConfig.GetIntValue(WorldCfg.MailLevelReq));
                return;
            }

            List <Item> items = new List <Item>();

            foreach (var att in packet.Info.Attachments)
            {
                if (att.ItemGUID.IsEmpty())
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.MailAttachmentInvalid);
                    return;
                }

                Item item = player.GetItemByGuid(att.ItemGUID);

                // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail)
                if (!item)
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.MailAttachmentInvalid);
                    return;
                }

                if (!item.CanBeTraded(true))
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
                    return;
                }

                if (item.IsBoundAccountWide() && item.IsSoulBound() && player.GetSession().GetAccountId() != receiverAccountId)
                {
                    if (!item.IsBattlenetAccountBound() || player.GetSession().GetBattlenetAccountId() == 0 || player.GetSession().GetBattlenetAccountId() != receiverBnetAccountId)
                    {
                        player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.NotSameAccount);
                        return;
                    }
                }

                if (item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || item.m_itemData.Expiration != 0)
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.MailBoundItem);
                    return;
                }

                if (packet.Info.Cod != 0 && item.HasItemFlag(ItemFieldFlags.Wrapped))
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.CantSendWrappedCod);
                    return;
                }

                if (item.IsNotEmptyBag())
                {
                    player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.DestroyNonemptyBag);
                    return;
                }

                items.Add(item);
            }

            player.SendMailResult(0, MailResponseType.Send, MailResponseResult.Ok);

            player.ModifyMoney(-reqmoney);
            player.UpdateCriteria(CriteriaTypes.GoldSpentForMail, cost);

            bool needItemDelay = false;

            MailDraft draft = new MailDraft(packet.Info.Subject, packet.Info.Body);

            SQLTransaction trans = new SQLTransaction();

            if (!packet.Info.Attachments.Empty() || packet.Info.SendMoney > 0)
            {
                bool log = HasPermission(RBACPermissions.LogGmTrade);
                if (!packet.Info.Attachments.Empty())
                {
                    foreach (var item in items)
                    {
                        if (log)
                        {
                            Log.outCommand(GetAccountId(), "GM {0} ({1}) (Account: {2}) mail item: {3} (Entry: {4} Count: {5}) to player: {6} ({7}) (Account: {8})",
                                           GetPlayerName(), GetPlayer().GetGUID().ToString(), GetAccountId(), item.GetTemplate().GetName(), item.GetEntry(), item.GetCount(),
                                           packet.Info.Target, receiverGuid.ToString(), receiverAccountId);
                        }

                        item.SetNotRefundable(GetPlayer()); // makes the item no longer refundable
                        player.MoveItemFromInventory(item.GetBagSlot(), item.GetSlot(), true);

                        item.DeleteFromInventoryDB(trans);     // deletes item from character's inventory
                        item.SetOwnerGUID(receiverGuid);
                        item.SetState(ItemUpdateState.Changed);
                        item.SaveToDB(trans);                  // recursive and not have transaction guard into self, item not in inventory and can be save standalone

                        draft.AddItem(item);
                    }

                    // if item send to character at another account, then apply item delivery delay
                    needItemDelay = player.GetSession().GetAccountId() != receiverAccountId;
                }

                if (log && packet.Info.SendMoney > 0)
                {
                    Log.outCommand(GetAccountId(), "GM {0} ({1}) (Account: {{2}) mail money: {3} to player: {4} ({5}) (Account: {6})",
                                   GetPlayerName(), GetPlayer().GetGUID().ToString(), GetAccountId(), packet.Info.SendMoney, packet.Info.Target, receiverGuid.ToString(), receiverAccountId);
                }
            }

            // If theres is an item, there is a one hour delivery delay if sent to another account's character.
            uint deliver_delay = needItemDelay ? WorldConfig.GetUIntValue(WorldCfg.MailDeliveryDelay) : 0;

            // Mail sent between guild members arrives instantly
            Guild guild = Global.GuildMgr.GetGuildById(player.GetGuildId());

            if (guild)
            {
                if (guild.IsMember(receiverGuid))
                {
                    deliver_delay = 0;
                }
            }

            // don't ask for COD if there are no items
            if (packet.Info.Attachments.Empty())
            {
                packet.Info.Cod = 0;
            }

            // will delete item or place to receiver mail list
            draft.AddMoney((ulong)packet.Info.SendMoney).AddCOD((uint)packet.Info.Cod).SendMailTo(trans, new MailReceiver(receiver, receiverGuid.GetCounter()), new MailSender(player), string.IsNullOrEmpty(packet.Info.Body) ? MailCheckMask.Copied : MailCheckMask.HasBody, deliver_delay);

            player.SaveInventoryAndGoldToDB(trans);
            DB.Characters.CommitTransaction(trans);
        }