/// %Log the player out void WorldSession::LogoutPlayer(bool Save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; m_playerSave = Save; if (_player) { if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat if (_player->GetDeathTimer()) { _player->getHostileRefManager().deleteReferences(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (!_player->getAttackers().empty()) { _player->CombatStop(); _player->getHostileRefManager().setOnlineOfflineState(false); _player->RemoveAllAurasOnDeath(); // build set of player who attack _player or who have pet attacking of _player std::set<Player*> aset; for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) { Unit* owner = (*itr)->GetOwner(); // including player controlled case if (owner && owner->GetTypeId() == TYPEID_PLAYER) aset.insert(owner->ToPlayer()); else if ((*itr)->GetTypeId() == TYPEID_PLAYER) aset.insert((Player*)(*itr)); } _player->SetPvPDeath(!aset.empty()); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); // give honor to all attackers from set like group case for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) (*itr)->RewardHonor(_player, aset.size()); // give bg rewards and update counters like kill by first from attackers // this can't be called for all attackers. if (!aset.empty()) if (Battleground* bg = _player->GetBattleground()) bg->HandleKillPlayer(_player, *aset.begin()); } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); _player->KillPlayer(); _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } else if (_player->HasPendingBind()) { _player->RepopAtGraveyard(); _player->SetPendingBind(0, 0); } //drop a flag if player is carrying it if (Battleground* bg = _player->GetBattleground()) bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if (!_player->m_InstanceValid && !_player->isGameMaster()) _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation()); sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId()); for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i)) { _player->RemoveBattlegroundQueueId(bgQueueTypeId); sBattlegroundMgr->m_BattlegroundQueues[ bgQueueTypeId ].RemovePlayer(_player->GetGUID(), true); } } // Repop at GraveYard or other player far teleport will prevent saving player because of not present map // Teleport player immediately for correct player save while (_player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) guild->HandleMemberLogout(this); ///- Remove pet _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (Save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) { eslot = j - BUYBACK_SLOT_START; _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0); _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0); } _player->SaveToDB(); } ///- Leave all channels before player delete... _player->CleanupChannels(); ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group. _player->UninviteFromGroup(); // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) _player->RemoveFromGroup(); ///- Send update to group and reset stored max enchanting level if (_player->GetGroup()) { _player->GetGroup()->SendUpdate(); _player->GetGroup()->ResetMaxEnchantingLevel(); } ///- Broadcast a logout message to the player's friends sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true); sSocialMgr->RemovePlayerSocial (_player->GetGUIDLow ()); // Call script hook before deletion sScriptMgr->OnPlayerLogout(GetPlayer()); ///- Remove the player from the world // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map // calls to GetMap in this case may cause crashes _player->CleanupsBeforeDelete(); sLog->outChar("Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName(), _player->GetGUIDLow(), _player->getLevel()); if (Map* _map = _player->FindMap()) _map->RemovePlayerFromMap(_player, true); SetPlayer(NULL); // deleted in Remove call ///- Send the 'logout complete' packet to the client WorldPacket data(SMSG_LOGOUT_COMPLETE, 0); SendPacket(&data); ///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline //No SQL injection as AccountId is uint32 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE); stmt->setUInt32(0, GetAccountId()); CharacterDatabase.Execute(stmt); sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } m_playerLogout = false; m_playerSave = false; m_playerRecentlyLogout = true; LogoutRequest(0); }
bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry) { // 0 1 2 3 4 5 6 7 8 9 10 //result = CharacterDatabase.PQuery("SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text FROM item_instance WHERE guid = '%u'", guid); // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB Object::_Create(guid, 0, HIGHGUID_ITEM); // Set entry, MUST be before proto check SetEntry(entry); SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); ItemTemplate const* proto = GetTemplate(); if (!proto) return false; // set owner (not if item is only loaded for gbank/auction/mail if (owner_guid != 0) SetOwnerGUID(owner_guid); bool need_save = false; // need explicit save data at load fixes SetUInt64Value(ITEM_FIELD_CREATOR, MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER)); SetUInt64Value(ITEM_FIELD_GIFTCREATOR, MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER)); SetCount(fields[2].GetUInt32()); uint32 duration = fields[3].GetUInt32(); SetUInt32Value(ITEM_FIELD_DURATION, duration); // update duration if need, and remove if not need if ((proto->Duration == 0) != (duration == 0)) { SetUInt32Value(ITEM_FIELD_DURATION, abs(proto->Duration)); need_save = true; } Tokens tokens(fields[4].GetString(), ' ', MAX_ITEM_PROTO_SPELLS); if (tokens.size() == MAX_ITEM_PROTO_SPELLS) for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) SetSpellCharges(i, atoi(tokens[i])); SetUInt32Value(ITEM_FIELD_FLAGS, fields[5].GetUInt32()); // Remove bind flag for items vs NO_BIND set if (IsSoulBound() && proto->Bonding == NO_BIND) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, false); need_save = true; } std::string enchants = fields[6].GetString(); _LoadIntoDataField(enchants.c_str(), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET); SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, fields[7].GetInt16()); // recalculate suffix factor if (GetItemRandomPropertyId() < 0) UpdateItemSuffixFactor(); uint32 durability = fields[8].GetUInt16(); SetUInt32Value(ITEM_FIELD_DURABILITY, durability); // update max durability (and durability) if need SetUInt32Value(ITEM_FIELD_MAXDURABILITY, proto->MaxDurability); if (durability > proto->MaxDurability) { SetUInt32Value(ITEM_FIELD_DURABILITY, proto->MaxDurability); need_save = true; } SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, fields[9].GetUInt32()); SetText(fields[10].GetString()); if (need_save) // normal item changed state set not work at loading { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_ITEM_INSTANCE_ON_LOAD); stmt->setUInt32(0, GetUInt32Value(ITEM_FIELD_DURATION)); stmt->setUInt32(1, GetUInt32Value(ITEM_FIELD_FLAGS)); stmt->setUInt32(2, GetUInt32Value(ITEM_FIELD_DURABILITY)); stmt->setUInt32(3, guid); CharacterDatabase.Execute(stmt); } return true; }
// this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_PLACE_BID"); uint64 auctioneer; uint32 auctionId; uint64 price; recvData >> auctioneer; recvData >> auctionId; recvData >> price; if (!auctionId || !price) return; // check for cheaters Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(auctioneer, UNIT_NPC_FLAG_AUCTIONEER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandleAuctionPlaceBid - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(auctioneer))); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(creature->getFaction()); AuctionEntry* auction = auctionHouse->GetAuction(auctionId); Player* player = GetPlayer(); if (!auction || auction->owner == player->GetGUIDLow()) { //you cannot bid your own auction: SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; } // impossible have online own another character (use this for speedup check in case online owner) /*Player* auction_owner = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)); if (!auction_owner && sObjectMgr->GetPlayerAccountIdByGUID(MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER)) == player->GetSession()->GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult(NULL, AUCTION_PLACE_BID, ERR_AUCTION_BID_OWN); return; }*/ // cheating if (price <= auction->bid || price < auction->startbid) return; // price too low for next bid if not buyout if ((price < auction->buyout || auction->buyout == 0) && price < auction->bid + auction->GetAuctionOutBid()) { // client already test it but just in case ... SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_HIGHER_BID); return; } if (!player->HasEnoughMoney(price)) { // client already test it but just in case ... SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_NOT_ENOUGHT_MONEY); return; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (price < auction->buyout || auction->buyout == 0) { if (auction->bidder > 0) { if (auction->bidder == player->GetGUIDLow()) player->ModifyMoney(-int64(price - auction->bid)); else { // mail to last bidder and return money sAuctionMgr->SendAuctionOutbiddedMail(auction, price, GetPlayer(), trans); player->ModifyMoney(-int64(price)); } } else player->ModifyMoney(-int64(price)); auction->bidder = player->GetGUIDLow(); auction->bid = price; GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_AUCTION_BID); stmt->setUInt32(0, auction->bidder); stmt->setUInt32(1, auction->bid); stmt->setUInt32(2, auction->Id); trans->Append(stmt); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); } else { //buyout: if (player->GetGUIDLow() == auction->bidder) player->ModifyMoney(-int64(auction->buyout - auction->bid)); else { player->ModifyMoney(-int64(auction->buyout)); if (auction->bidder) //buyout for bidded auction .. sAuctionMgr->SendAuctionOutbiddedMail(auction, auction->buyout, GetPlayer(), trans); } auction->bidder = player->GetGUIDLow(); auction->bid = auction->buyout; GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout); //- Mails must be under transaction control too to prevent data loss sAuctionMgr->SendAuctionSalePendingMail(auction, trans); sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); SendAuctionCommandResult(auction, AUCTION_PLACE_BID, ERR_AUCTION_OK); auction->DeleteFromDB(trans); uint32 itemEntry = auction->itemEntry; sAuctionMgr->RemoveAItem(auction->itemGUIDLow); auctionHouse->RemoveAuction(auction, itemEntry); } player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandleTurnInPetitionOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_TURN_IN_PETITION"); // Get petition guid from packet WorldPacket data; ObjectGuid petitionGuid; recvData.ReadGuidMask(petitionGuid, 1, 2, 3, 0, 5, 7, 4, 6); recvData.ReadGuidBytes(petitionGuid, 2, 1, 4, 6, 0, 7, 5, 3); // Check if player really has the required petition charter Item* item = _player->GetItemByGuid(petitionGuid); if (!item) return; TC_LOG_DEBUG("network", "Petition %u turned in by %u", GUID_LOPART(petitionGuid), _player->GetGUIDLow()); // Get petition data from db uint32 ownerguidlo; uint32 type; std::string name; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); ownerguidlo = fields[0].GetUInt32(); name = fields[1].GetString(); type = fields[2].GetUInt8(); } else { TC_LOG_ERROR("network", "Player %s (guid: %u) tried to turn in petition (guid: %u) that is not present in the database", _player->GetName().c_str(), _player->GetGUIDLow(), GUID_LOPART(petitionGuid)); return; } // Only the petition owner can turn in the petition if (_player->GetGUIDLow() != ownerguidlo) return; // Petition type (guild/arena) specific checks // Check if player is already in a guild if (_player->GetGuildId()) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 1); data.WriteBits(PETITION_TURN_ALREADY_IN_GUILD, 4); data.FlushBits(); _player->GetSession()->SendPacket(&data); return; } // Check if guild name is already taken if (sGuildMgr->GetGuildByName(name)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, name); return; } // Get petition signatures from db uint8 signatures; stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); result = CharacterDatabase.Query(stmt); if (result) signatures = uint8(result->GetRowCount()); else signatures = 0; uint32 requiredSignatures; if (type == GUILD_CHARTER_TYPE) requiredSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS); else requiredSignatures = type-1; // Notify player if signatures are missing if (signatures < requiredSignatures) { data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 1); data.WriteBits(PETITION_TURN_NEED_MORE_SIGNATURES, 4); data.FlushBits(); SendPacket(&data); return; } // Proceed with guild/arena team creation // Delete charter item _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); // Create guild Guild* guild = new Guild; if (!guild->Create(_player, name)) { delete guild; return; } // Register guild and add guild master sGuildMgr->AddGuild(guild); Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_COMMAND_SUCCESS, name); // Add members from signatures for (uint8 i = 0; i < signatures; ++i) { Field* fields = result->Fetch(); guild->AddMember(MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER)); result->NextRow(); } SQLTransaction trans = CharacterDatabase.BeginTransaction(); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_BY_GUID); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PETITION_SIGNATURE_BY_GUID); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); // created TC_LOG_DEBUG("network", "TURN IN PETITION GUID %u", GUID_LOPART(petitionGuid)); data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 1); data.WriteBits(PETITION_TURN_OK, 4); data.FlushBits(); SendPacket(&data); }
// teleport player to given game_tele.entry static bool HandleTeleNameCommand(ChatHandler* handler, const char* args) { char* nameStr; char* teleStr; handler->extractOptFirstArg((char*)args, &nameStr, &teleStr); if (!teleStr) return false; Player* target; ObjectGuid target_guid; std::string target_name; if (!handler->extractPlayerTarget(nameStr, &target, &target_guid, &target_name)) return false; if (strcmp(teleStr, "$home") == 0) // References target's homebind { if (target) target->TeleportTo(target->m_homebindMapId, target->m_homebindX, target->m_homebindY, target->m_homebindZ, target->GetOrientation()); else { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_HOMEBIND); stmt->setUInt32(0, target_guid.GetCounter()); PreparedQueryResult resultDB = CharacterDatabase.Query(stmt); if (resultDB) { Field* fieldsDB = resultDB->Fetch(); WorldLocation loc(fieldsDB[0].GetUInt16(), fieldsDB[2].GetFloat(), fieldsDB[3].GetFloat(), fieldsDB[4].GetFloat(), 0.0f); uint32 zoneId = fieldsDB[1].GetUInt16(); SQLTransaction dummy; Player::SavePositionInDB(loc, zoneId, target_guid, dummy); } } return true; } // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r GameTele const* tele = handler->extractGameTeleFromLink(teleStr); if (!tele) { handler->SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); handler->SetSentErrorMessage(true); return false; } if (target) { // check online security if (handler->HasLowerSecurity(target, ObjectGuid::Empty)) return false; std::string chrNameLink = handler->playerLink(target_name); if (target->IsBeingTeleported() == true) { handler->PSendSysMessage(LANG_IS_TELEPORTED, chrNameLink.c_str()); handler->SetSentErrorMessage(true); return false; } handler->PSendSysMessage(LANG_TELEPORTING_TO, chrNameLink.c_str(), "", tele->name.c_str()); if (handler->needReportToTarget(target)) ChatHandler(target->GetSession()).PSendSysMessage(LANG_TELEPORTED_TO_BY, handler->GetNameLink().c_str()); // stop flight if need if (target->IsInFlight()) { target->GetMotionMaster()->MovementExpired(); target->CleanupAfterTaxiFlight(); } // save only in non-flight case else target->SaveRecallPosition(); target->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); } else { // check offline security if (handler->HasLowerSecurity(NULL, target_guid)) return false; std::string nameLink = handler->playerLink(target_name); handler->PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), handler->GetTrinityString(LANG_OFFLINE), tele->name.c_str()); SQLTransaction dummy; Player::SavePositionInDB(WorldLocation(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation), sMapMgr->GetZoneId(tele->mapId, tele->position_x, tele->position_y, tele->position_z), target_guid, dummy); } return true; }
void WorldSession::HandlePetitionRenameOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_RENAME"); ObjectGuid petitionGuid; uint32 type; uint8 nameLen; std::string newName; nameLen = recvData.ReadBits(7); recvData.ReadGuidMask(petitionGuid, 7, 4, 6, 2, 0, 5, 3, 1); recvData.ReadGuidBytes(petitionGuid, 4, 1, 7); newName = recvData.ReadString(nameLen); recvData.ReadGuidBytes(petitionGuid, 0, 3, 2, 6, 5); Item* item = _player->GetItemByGuid(petitionGuid); if (!item) return; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_TYPE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); type = fields[0].GetUInt8(); } else { TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionGuid)); return; } if (sGuildMgr->GetGuildByName(newName)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, newName); return; } if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_INVALID, newName); return; } stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); stmt->setString(0, newName); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); CharacterDatabase.Execute(stmt); TC_LOG_DEBUG("network", "Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionGuid), newName.c_str()); WorldPacket data(SMSG_PETITION_RENAME_RESULT, (9 + 1 + newName.size())); data.WriteBits(newName.length(), 7); data.WriteGuidMask(petitionGuid, 0, 3, 4, 2, 6, 5, 7, 1); data.WriteGuidBytes(petitionGuid, 4, 3, 6, 0, 5, 2, 1, 7); data.WriteString(newName); SendPacket(&data); }
void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_BUY"); ObjectGuid guid; recvData.ReadGuidMask(guid, 5, 2, 3); uint8 nameLength = recvData.ReadBits(7); recvData.ReadGuidMask(guid, 4, 1, 7, 0, 6); std::string name = recvData.ReadString(nameLength); recvData.ReadGuidBytes(guid, 1, 7, 4, 6, 0, 5, 2, 3); TC_LOG_DEBUG("network", "Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guid), name.c_str()); // prevent cheating Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_PETITIONER); if (!creature) { TC_LOG_DEBUG("network", "WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guid)); return; } // remove fake death if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); uint32 charterid = 0; uint32 cost = 0; uint32 type = 0; // if tabard designer, then trying to buy a guild charter. // do not let if already in guild. if (_player->GetGuildId()) return; charterid = GUILD_CHARTER; cost = GUILD_CHARTER_COST; type = GUILD_CHARTER_TYPE; if (sGuildMgr->GetGuildByName(name)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, name); return; } if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_INVALID, name); return; } ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(charterid); if (!pProto) { _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0); return; } if (!_player->HasEnoughMoney(uint64(cost))) { //player hasn't got enough money _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterid, 0); return; } ItemPosCountVec dest; InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount); if (msg != EQUIP_ERR_OK) { _player->SendEquipError(msg, NULL, NULL, charterid); return; } _player->ModifyMoney(-(int32)cost); Item* charter = _player->StoreNewItem(dest, charterid, true); if (!charter) return; //I think this has changed charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT, charter->GetGUIDLow()); // ITEM_FIELD_ENCHANTMENT is guild/arenateam id // ITEM_FIELD_ENCHANTMENT+1 is current signatures count (showed on item) charter->SetState(ITEM_CHANGED, _player); _player->SendNewItem(charter, 1, true, false); // a petition is invalid, if both the owner and the type matches // we checked above, if this player is in an arenateam, so this must be // datacorruption PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_BY_OWNER); stmt->setUInt32(0, _player->GetGUIDLow()); stmt->setUInt8(1, type); PreparedQueryResult result = CharacterDatabase.Query(stmt); std::ostringstream ssInvalidPetitionGUIDs; if (result) { do { Field* fields = result->Fetch(); ssInvalidPetitionGUIDs << '\'' << fields[0].GetUInt32() << "', "; } while (result->NextRow()); } // delete petitions with the same guid as this one ssInvalidPetitionGUIDs << '\'' << charter->GetGUIDLow() << '\''; //Probably DB Charter Petitions has changed too TC_LOG_DEBUG("network", "Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.EscapeString(name); SQLTransaction trans = CharacterDatabase.BeginTransaction(); trans->PAppend("DELETE FROM petition WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); trans->PAppend("DELETE FROM petition_sign WHERE petitionguid IN (%s)", ssInvalidPetitionGUIDs.str().c_str()); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION); stmt->setUInt32(0, _player->GetGUIDLow()); stmt->setUInt32(1, charter->GetGUIDLow()); stmt->setString(2, name); stmt->setUInt8(3, uint8(type)); //Type no needed anymore trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); }
void AuctionEntry::SaveToDB(SQLTransaction& trans) const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AUCTION); stmt->setUInt32(0, Id); stmt->setUInt32(1, auctioneer); stmt->setUInt32(2, itemGUIDLow); stmt->setUInt32(3, owner); stmt->setUInt32(4, buyout); stmt->setUInt32(5, uint32(expire_time)); stmt->setUInt32(6, bidder); stmt->setUInt32(7, bid); stmt->setUInt32(8, startbid); stmt->setUInt32(9, deposit); trans->Append(stmt); }
void AuctionHouseMgr::DeleteExpiredAuctionsAtStartup() { // Deletes expired auctions. Should be called at server start before loading auctions. // DO NOT USE after auctions are already loaded since this deletes from the DB // and assumes the auctions HAVE NOT been loaded into a list or AuctionEntryMap yet uint32 oldMSTime = getMSTime(); uint32 expirecount = 0; time_t curTime = sWorld->GetGameTime(); // Query the DB to see if there are any expired auctions PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_AUCTIONS); stmt->setUInt32(0, (uint32)curTime+60); PreparedQueryResult expAuctions = CharacterDatabase.Query(stmt); if (!expAuctions) { sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> No expired auctions to delete"); return; } do { Field* fields = expAuctions->Fetch(); AuctionEntry* auction = new AuctionEntry(); // Can't use LoadFromDB() because it assumes the auction map is loaded if (!auction->LoadFromFieldList(fields)) { // For some reason the record in the DB is broken (possibly corrupt // faction info). Delete the object and move on. delete auction; continue; } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (auction->bidder==0) { // Cancel the auction, there was no bidder sAuctionMgr->SendAuctionExpiredMail(auction, trans); } else { // Send the item to the winner and money to seller sAuctionMgr->SendAuctionSuccessfulMail(auction, trans); sAuctionMgr->SendAuctionWonMail(auction, trans); } // Call the appropriate AuctionHouseObject script // ** Do we need to do this while core is still loading? ** sScriptMgr->OnAuctionExpire(GetAuctionsMap(auction->factionTemplateId), auction); // Delete the auction from the DB auction->DeleteFromDB(trans); CharacterDatabase.CommitTransaction(trans); // Release memory delete auction; ++expirecount; } while (expAuctions->NextRow()); sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Deleted %u expired auctions in %u ms", expirecount, GetMSTimeDiffToNow(oldMSTime)); }
void Corpse::SaveToDB() { // prevent DB data inconsistence problems and duplicates SQLTransaction trans = CharacterDatabase.BeginTransaction(); DeleteFromDB(trans); uint16 index = 0; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE); stmt->setUInt32(index++, GetGUIDLow()); // corpseGuid stmt->setUInt32(index++, GUID_LOPART(GetOwnerGUID())); // guid stmt->setFloat (index++, GetPositionX()); // posX stmt->setFloat (index++, GetPositionY()); // posY stmt->setFloat (index++, GetPositionZ()); // posZ stmt->setFloat (index++, GetOrientation()); // orientation stmt->setUInt16(index++, GetMapId()); // mapId stmt->setUInt32(index++, GetUInt32Value(CORPSE_FIELD_DISPLAY_ID)); // displayId stmt->setString(index++, _ConcatFields(CORPSE_FIELD_ITEMS, EQUIPMENT_SLOT_END)); // itemCache stmt->setUInt32(index++, GetUInt32Value(CORPSE_FIELD_SKIN_ID)); // bytes1 stmt->setUInt32(index++, GetUInt32Value(CORPSE_FIELD_FACIAL_HAIR_STYLE_ID)); // bytes2 stmt->setUInt8 (index++, GetUInt32Value(CORPSE_FIELD_FLAGS)); // flags stmt->setUInt8 (index++, GetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS)); // dynFlags stmt->setUInt32(index++, uint32(m_time)); // time stmt->setUInt8 (index++, GetType()); // corpseType stmt->setUInt32(index++, GetInstanceId()); // instanceId stmt->setUInt32(index++, GetPhaseMask()); // phaseMask trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); }
void AuctionEntry::DeleteFromDB(SQLTransaction& trans) const { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_AUCTION); stmt->setUInt32(0, Id); trans->Append(stmt); }
void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) { uint8 arenaType; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1 uint32 bgTypeId_; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 recvData >> arenaType >> unk2 >> bgTypeId_ >> unk >> action; // bgTypeId not valid if (!sBattlemasterListStore.LookupEntry(bgTypeId_)) return; // player not in any queue, so can't really answer if (!_player->InBattlegroundQueue()) return; // get BattlegroundQueue for received BattlegroundTypeId bgTypeId = BattlegroundTypeId(bgTypeId_); BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(bgTypeId, arenaType); BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId); // get group info from queue GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) return; // to accept, player must be invited to particular battleground id if (!ginfo.IsInvitedToBGInstanceGUID && action == 1) return; Battleground* bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID); // use template if leaving queue (instance might not be created yet) if (!bg && action == 0) bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) return; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) return; // safety checks if (action == 1 && ginfo.ArenaType == 0) { // can't join with deserter, check it here right before joining to be sure if (!_player->CanJoinToBattleground()) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); SendPacket(&data); action = 0; } if (_player->getLevel() > bg->GetMaxLevel()) action = 0; } // get player queue slot index for this bg (can be in up to 2 queues at the same time) uint32 queueSlot = _player->GetBattlegroundQueueIndex(bgQueueTypeId); WorldPacket data; switch (action) { case 1: // accept { // set entry point if not in battleground if (!_player->InBattleground()) _player->SetEntryPoint(); // resurrect the player if (!_player->IsAlive()) { _player->ResurrectPlayer(1.0f); _player->SpawnCorpseBones(); } TeamId teamId = ginfo.teamId; // remove player from all bg queues for (uint32 qslot = 0; qslot < PLAYER_MAX_BATTLEGROUND_QUEUES; ++qslot) if (BattlegroundQueueTypeId q = _player->GetBattlegroundQueueTypeId(qslot)) { BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(q); queue.RemovePlayer(_player->GetGUID(), (bgQueueTypeId == q), qslot); _player->RemoveBattlegroundQueueId(q); } // send status packet sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), teamId); SendPacket(&data); _player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, teamId); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); } break; case 0: // leave queue { bgQueue.RemovePlayer(_player->GetGUID(), false, queueSlot); _player->RemoveBattlegroundQueueId(bgQueueTypeId); // track if player refuses to join the BG after being invited if (bg->isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS) && (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK); stmt->setUInt32(0, _player->GetGUIDLow()); stmt->setUInt8(1, BG_DESERTION_TYPE_LEAVE_QUEUE); CharacterDatabase.Execute(stmt); } } break; default: break; } }
AccountOpResult DeleteAccount(uint32 accountId) { // Check if accounts exists PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); stmt->setUInt32(0, accountId); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) return AOR_NAME_NOT_EXIST; // Obtain accounts characters stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID); stmt->setUInt32(0, accountId); result = CharacterDatabase.Query(stmt); if (result) { do { uint32 guidLow = (*result)[0].GetUInt32(); uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); // Kick if player is online if (Player* p = ObjectAccessor::FindPlayer(guid)) { WorldSession* s = p->GetSession(); s->KickPlayer(); // mark session to remove at next session list update s->LogoutPlayer(false); // logout player without waiting next session list update } Player::DeleteFromDB(guid, accountId, false); // no need to update realm characters } while (result->NextRow()); } // table realm specific but common for all characters of account for realm stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS); stmt->setUInt32(0, accountId); CharacterDatabase.Execute(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA); stmt->setUInt32(0, accountId); CharacterDatabase.Execute(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN); stmt->setUInt32(0, accountId); CharacterDatabase.Execute(stmt); SQLTransaction trans = LoginDatabase.BeginTransaction(); stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT); stmt->setUInt32(0, accountId); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); stmt->setUInt32(0, accountId); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS); stmt->setUInt32(0, accountId); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_BANNED); stmt->setUInt32(0, accountId); trans->Append(stmt); LoginDatabase.CommitTransaction(trans); return AOR_OK; }
void WorldSession::LoadGlobalAccountData() { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA); stmt->setUInt32(0, GetAccountId()); LoadAccountData(CharacterDatabase.Query(stmt), GLOBAL_CACHE_MASK); }
void WorldSession::HandlePetitionShowSignOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_SHOW_SIGNATURES"); uint8 playerCount = 0; ObjectGuid petitionGuid; recvData.ReadGuidMask(petitionGuid, 3, 7, 2, 4, 5, 6, 0, 1); recvData.ReadGuidBytes(petitionGuid, 2, 4, 5, 7, 1, 0, 3, 6); // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) uint32 petitionGuidLow = GUID_LOPART(petitionGuid); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_TYPE); stmt->setUInt32(0, petitionGuidLow); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_DEBUG("entities.player.items", "Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName().c_str()); return; } Field* fields = result->Fetch(); uint32 type = fields[0].GetUInt8(); // if guild petition and has guild => error, return; if (type == GUILD_CHARTER_TYPE && _player->GetGuildId()) return; stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt32(0, petitionGuidLow); result = CharacterDatabase.Query(stmt); // result == NULL also correct in case no sign yet if (result) playerCount = uint8(result->GetRowCount()); TC_LOG_DEBUG("network", "CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionGuidLow); ObjectGuid playerGuid = _player->GetGUID(); ObjectGuid* playerGuids = new ObjectGuid[playerCount]; for (uint8 i = 0; i < playerCount; ++i) { Field* fields2 = result->Fetch(); uint32 lowGuid = fields2[0].GetUInt32(); playerGuids[i] = MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER); result->NextRow(); } WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (9 + 9 + 3 + 4 + playerCount * (9 + 4))); data.WriteBit(playerGuid[1]); data.WriteBit(petitionGuid[3]); data.WriteBit(playerGuid[3]); data.WriteGuidMask(petitionGuid, 4, 0); data.WriteGuidMask(playerGuid, 7, 5); data.WriteGuidMask(petitionGuid, 1, 5, 7); data.WriteGuidMask(playerGuid, 0, 6); data.WriteBit(petitionGuid[6]); data.WriteGuidMask(playerGuid, 2, 4); data.WriteBits(playerCount, 21); for (int i = 0; i < playerCount; i++) { data.WriteGuidMask(playerGuids[i], 2, 0, 4, 7, 5, 1, 6, 3); } data.WriteBit(petitionGuid[2]); data.FlushBits(); for (int i = 0; i < playerCount; i++) { data.WriteGuidBytes(playerGuids[i], 6, 0, 1, 3, 2, 5, 7, 4); data << uint32(1); // Choice ??? Blizzard also stores declined players ??? } data.WriteGuidBytes(petitionGuid, 6, 5, 4); data.WriteByteSeq(playerGuid[4]); data.WriteByteSeq(petitionGuid[1]); data << uint32(petitionGuidLow); // guildID data.WriteGuidBytes(petitionGuid, 2, 3, 7); data.WriteGuidBytes(playerGuid, 5, 6, 3, 7, 1, 0); data.WriteByteSeq(petitionGuid[0]); data.WriteByteSeq(playerGuid[2]); delete[] playerGuids; SendPacket(&data); }
//does not clear ram void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& trans) { Item* pItem = GetAItem(auction->itemGUIDLow); if (!pItem) return; uint32 bidderAccId = 0; uint64 bidderGuid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); Player* bidder = ObjectAccessor::FindPlayer(bidderGuid); // data for gm.log std::string bidderName; bool logGmTrade = false; if (bidder) { bidderAccId = bidder->GetSession()->GetAccountId(); bidderName = bidder->GetName(); logGmTrade = bidder->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE); } else { bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid); logGmTrade = AccountMgr::HasPermission(bidderAccId, RBAC_PERM_LOG_GM_TRADE, realmID); if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName)) bidderName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); } if (logGmTrade) { std::string ownerName; if (!sObjectMgr->GetPlayerNameByGUID(auction->owner, ownerName)) ownerName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); uint32 ownerAccId = sObjectMgr->GetPlayerAccountIdByGUID(auction->owner); sLog->outCommand(bidderAccId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", bidderName.c_str(), bidderAccId, pItem->GetTemplate()->Name1.c_str(), pItem->GetEntry(), pItem->GetCount(), auction->bid, ownerName.c_str(), ownerAccId); } // receiver exist if (bidder || bidderAccId) { // set owner to bidder (to prevent delete item with sender char deleting) // owner in `data` will set at mail receive and item extracting PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER); stmt->setUInt32(0, auction->bidder); stmt->setUInt32(1, pItem->GetGUIDLow()); trans->Append(stmt); if (bidder) { bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidderGuid, 0, 0, auction->itemEntry); // FIXME: for offline player need also bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1); } MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, 0, 0)) .AddItem(pItem) .SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED); } }
void WorldSession::SendPetitionQueryOpcode(uint64 petitionGuid) { ObjectGuid ownerGuid = 0; uint32 type; std::string name = "NO_NAME_FOR_GUID"; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); name = fields[1].GetString(); type = fields[2].GetUInt8(); } else { TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionGuid)); return; } WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10)); data << uint32(GUID_LOPART(petitionGuid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) data.WriteBit(1); // hasData; for (int i = 0; i < 10; i++) data.WriteBits(0, 6); // Unk strings; data.WriteGuidMask(ownerGuid, 2, 4); data.WriteBits(0, 12); data.WriteGuidMask(ownerGuid, 0, 7, 3, 6, 5); data.WriteBits(name.size(), 7); //NameLen data.WriteBit(ownerGuid[1]); data.FlushBits(); data.WriteByteSeq(ownerGuid[5]); data << uint32(0); data.WriteString(name); data << uint32(0); data.WriteByteSeq(ownerGuid[4]); data << uint32(type); // Type - 4 guild data.WriteByteSeq(ownerGuid[6]); data << uint32(0); data << uint32(sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS)); // Required sign count data.WriteGuidBytes(ownerGuid, 1, 7, 0); data << uint32(0); data << uint32(0); data.WriteByteSeq(ownerGuid[2]); data << uint32(time(NULL) + YEAR); // Deadline data << uint16(0); data << uint32(0); data.WriteByteSeq(ownerGuid[3]); data << uint32(0); data << uint32(0); data << uint32(0); data << uint32(0); SendPacket(&data); }
bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor) { // Check if captain is present if (!ObjectAccessor::FindPlayer(captainGuid)) return false; // Check if arena team name is already taken if (sArenaTeamMgr->GetArenaTeamByName(TeamName)) return false; // Generate new arena team id TeamId = sArenaTeamMgr->GenerateArenaTeamId(); // Assign member variables CaptainGuid = captainGuid; Type = type; TeamName = teamName; BackgroundColor = backgroundColor; EmblemStyle = emblemStyle; EmblemColor = emblemColor; BorderStyle = borderStyle; BorderColor = borderColor; uint32 captainLowGuid = GUID_LOPART(captainGuid); // Save arena team to db PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM); stmt->setUInt32(0, TeamId); stmt->setString(1, TeamName); stmt->setUInt32(2, captainLowGuid); stmt->setUInt8(3, Type); stmt->setUInt16(4, Stats.Rating); stmt->setUInt32(5, BackgroundColor); stmt->setUInt8(6, EmblemStyle); stmt->setUInt32(7, EmblemColor); stmt->setUInt8(8, BorderStyle); stmt->setUInt32(9, BorderColor); CharacterDatabase.Execute(stmt); // Add captain as member AddMember(CaptainGuid); sLog->outArena("New ArenaTeam created [Id: %u] [Type: %u] [Captain low GUID: %u]", GetId(), GetType(), captainLowGuid); return true; }
void WorldSession::HandlePetitionSignOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_PETITION_SIGN"); // ok Field* fields; ObjectGuid petitionGuid; recvData.read_skip<uint8>(); recvData.ReadGuidMask(petitionGuid, 4, 2, 0, 1, 5, 3, 6, 7); recvData.ReadGuidBytes(petitionGuid, 6, 1, 7, 2, 5, 3, 0, 4); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURES); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) { TC_LOG_ERROR("network", "Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName().c_str()); return; } fields = result->Fetch(); uint64 ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); uint64 signs = fields[1].GetUInt64(); uint8 type = fields[2].GetUInt8(); uint32 playerGuid = _player->GetGUIDLow(); if (GUID_LOPART(ownerGuid) == playerGuid) return; // not let enemies sign guild charter if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(ownerGuid)) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); return; } if (_player->GetGuildId()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, _player->GetName()); return; } if (_player->GetGuildIdInvited()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); return; } if (++signs > type) // client signs maximum return; // Client doesn't allow to sign petition two times by one character, but not check sign by another character from same account // not allow sign another player from already sign player account stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIG_BY_ACCOUNT); stmt->setUInt32(0, GetAccountId()); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); result = CharacterDatabase.Query(stmt); if (result) { // close at signer side SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_ALREADY_SIGNED); return; } stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(ownerGuid)); stmt->setUInt32(1, GUID_LOPART(petitionGuid)); stmt->setUInt32(2, playerGuid); stmt->setUInt32(3, GetAccountId()); CharacterDatabase.Execute(stmt); TC_LOG_DEBUG("network", "PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionGuid), _player->GetName().c_str(), playerGuid, GetAccountId()); // close at signer side SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_OK); // update signs count on charter, required testing... //Item* item = _player->GetItemByGuid(petitionguid)); //if (item) // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+1, signs); // update for owner if online if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) owner->GetSession()->SendPetitionSignResults(petitionGuid, _player->GetGUID(), PETITION_SIGN_OK); }
void ArenaTeam::SaveToDB() { // Save team and member stats to db // Called after a match has ended or when calculating arena_points SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_STATS); stmt->setUInt16(0, Stats.Rating); stmt->setUInt16(1, Stats.WeekGames); stmt->setUInt16(2, Stats.WeekWins); stmt->setUInt16(3, Stats.SeasonGames); stmt->setUInt16(4, Stats.SeasonWins); stmt->setUInt32(5, Stats.Rank); stmt->setUInt32(6, GetId()); trans->Append(stmt); for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_MEMBER); stmt->setUInt16(0, itr->PersonalRating); stmt->setUInt16(1, itr->WeekGames); stmt->setUInt16(2, itr->WeekWins); stmt->setUInt16(3, itr->SeasonGames); stmt->setUInt16(4, itr->SeasonWins); stmt->setUInt32(5, GetId()); stmt->setUInt32(6, GUID_LOPART(itr->Guid)); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHARACTER_ARENA_STATS); stmt->setUInt32(0, GUID_LOPART(itr->Guid)); stmt->setUInt8(1, GetSlot()); stmt->setUInt16(2, itr->MatchMakerRating); trans->Append(stmt); } CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandleOfferPetitionOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "Received opcode CMSG_OFFER_PETITION"); // ok uint8 playerCount = 0; ObjectGuid petitionGuid, playerGuid; uint32 type; Player* player; recvData.read_skip<uint32>(); recvData.ReadGuidMask(playerGuid, 4, 1); petitionGuid[2] = recvData.ReadBit(); playerGuid[6] = recvData.ReadBit(); petitionGuid[1] = recvData.ReadBit(); playerGuid[2] = recvData.ReadBit(); petitionGuid[4] = recvData.ReadBit(); recvData.ReadGuidMask(playerGuid, 3, 7); recvData.ReadGuidMask(petitionGuid, 0, 6); recvData.ReadGuidMask(playerGuid, 5, 0); recvData.ReadGuidMask(petitionGuid, 3, 5, 7); recvData.ReadByteSeq(playerGuid[7]); recvData.ReadGuidBytes(petitionGuid, 1, 4, 2); recvData.ReadByteSeq(playerGuid[6]); recvData.ReadGuidBytes(petitionGuid, 3, 0, 5); recvData.ReadGuidBytes(playerGuid, 0, 2, 5, 3, 4); recvData.ReadByteSeq(petitionGuid[7]); recvData.ReadByteSeq(playerGuid[1]); recvData.ReadByteSeq(petitionGuid[6]); player = ObjectAccessor::FindPlayer(playerGuid); if (!player) return; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_TYPE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) return; Field* fields = result->Fetch(); type = fields[0].GetUInt8(); TC_LOG_DEBUG("network", "OFFER PETITION: type %u, GUID1 %u, to player id: %u", type, GUID_LOPART(petitionGuid), GUID_LOPART(playerGuid)); if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) { Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NOT_ALLIED); return; } if (player->GetGuildId()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_IN_GUILD_S, _player->GetName()); return; } if (player->GetGuildIdInvited()) { Guild::SendCommandResult(this, GUILD_COMMAND_INVITE, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); return; } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PETITION_SIGNATURE); stmt->setUInt32(0, GUID_LOPART(petitionGuid)); result = CharacterDatabase.Query(stmt); // result == NULL also correct charter without signs if (result) playerCount = uint8(result->GetRowCount()); ObjectGuid* playerGuids = new ObjectGuid[playerCount]; for (uint8 i = 0; i < playerCount; ++i) { Field* fields2 = result->Fetch(); uint32 lowGuid = fields2[0].GetUInt32(); playerGuids[i] = MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER); result->NextRow(); } WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (9 + 9 + 3 + 4 + playerCount * (9 + 4))); data.WriteBit(playerGuid[1]); data.WriteBit(petitionGuid[3]); data.WriteBit(playerGuid[3]); data.WriteGuidMask(petitionGuid, 4, 0); data.WriteGuidMask(playerGuid, 7, 5); data.WriteGuidMask(petitionGuid, 1, 5, 7); data.WriteGuidMask(playerGuid, 0, 6); data.WriteBit(petitionGuid[6]); data.WriteGuidMask(playerGuid, 2, 4); data.WriteBits(playerCount, 21); for (int i = 0; i < playerCount; i++) { data.WriteGuidMask(playerGuids[i], 2, 0, 4, 7, 5, 1, 6, 3); } data.WriteBit(petitionGuid[2]); data.FlushBits(); for (int i = 0; i < playerCount; i++) { data.WriteGuidBytes(playerGuids[i], 6, 0, 1, 3, 2, 5, 7, 4); data << uint32(1); // Choice ??? Blizzard also stores declined players ??? } data.WriteGuidBytes(petitionGuid, 6, 5, 4); data.WriteByteSeq(playerGuid[4]); data.WriteByteSeq(petitionGuid[1]); data << uint32(GUID_LOPART(petitionGuid)); // guildID data.WriteGuidBytes(petitionGuid, 2, 3, 7); data.WriteGuidBytes(playerGuid, 5, 6, 3, 7, 1, 0); data.WriteByteSeq(petitionGuid[0]); data.WriteByteSeq(playerGuid[2]); delete[] playerGuids; player->GetSession()->SendPacket(&data); }
bool ArenaTeam::AddMember(uint64 playerGuid) { std::string playerName; uint8 playerClass; // Check if arena team is full (Can't have more than type * 2 players) if (GetMembersSize() >= GetType() * 2) return false; // Get player name and class either from db or ObjectMgr Player* player = ObjectAccessor::FindPlayer(playerGuid); if (player) { playerClass = player->getClass(); playerName = player->GetName(); } else { // 0 1 // SELECT name, class FROM characters WHERE guid = ? PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_NAME_CLASS); stmt->setUInt32(0, GUID_LOPART(playerGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) return false; playerName = (*result)[0].GetString(); playerClass = (*result)[1].GetUInt8(); } // Check if player is already in a similar arena team if ((player && player->GetArenaTeamId(GetSlot())) || Player::GetArenaTeamIdFromDB(playerGuid, GetType()) != 0) { sLog->outError("Arena: Player %s (guid: %u) already has an arena team of type %u", playerName.c_str(), GUID_LOPART(playerGuid), GetType()); return false; } // Set player's personal rating uint32 personalRating = 0; if (sWorld->getIntConfig(CONFIG_ARENA_START_PERSONAL_RATING) > 0) personalRating = sWorld->getIntConfig(CONFIG_ARENA_START_PERSONAL_RATING); else if (GetRating() >= 1000) personalRating = 1000; // Try to get player's match maker rating from db and fall back to config setting if not found PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MATCH_MAKER_RATING); stmt->setUInt32(0, GUID_LOPART(playerGuid)); stmt->setUInt8(1, GetSlot()); PreparedQueryResult result = CharacterDatabase.Query(stmt); uint32 matchMakerRating; if (result) matchMakerRating = (*result)[0].GetUInt16(); else matchMakerRating = sWorld->getIntConfig(CONFIG_ARENA_START_MATCHMAKER_RATING); // Remove all player signatures from other petitions // This will prevent player from joining too many arena teams and corrupt arena team data integrity Player::RemovePetitionsAndSigns(playerGuid, GetType()); // Feed data to the struct ArenaTeamMember newMember; newMember.Name = playerName; newMember.Guid = playerGuid; newMember.Class = playerClass; newMember.SeasonGames = 0; newMember.WeekGames = 0; newMember.SeasonWins = 0; newMember.WeekWins = 0; newMember.PersonalRating = personalRating; newMember.MatchMakerRating = matchMakerRating; Members.push_back(newMember); // Save player's arena team membership to db stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM_MEMBER); stmt->setUInt32(0, TeamId); stmt->setUInt32(1, GUID_LOPART(playerGuid)); CharacterDatabase.Execute(stmt); // Inform player if online if (player) { player->SetInArenaTeam(TeamId, GetSlot(), GetType()); player->SetArenaTeamIdInvited(0); // Hide promote/remove buttons if (CaptainGuid != playerGuid) player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1); } sLog->outArena("Player: %s [GUID: %u] joined arena team type: %u [Id: %u].", playerName.c_str(), GUID_LOPART(playerGuid), GetType(), GetId()); return true; }
static bool HandleAddDisables(ChatHandler* handler, char const* args, uint8 disableType) { char* entryStr = strtok((char*)args, " "); if (!entryStr || !atoi(entryStr)) return false; char* flagsStr = strtok(NULL, " "); uint8 flags = flagsStr ? uint8(atoi(flagsStr)) : 0; char* commentStr = strtok(NULL, ""); if (!commentStr) return false; std::string disableComment = commentStr; uint32 entry = uint32(atoi(entryStr)); std::string disableTypeStr = ""; switch (disableType) { case DISABLE_TYPE_SPELL: { if (!sSpellMgr->GetSpellInfo(entry)) { handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "spell"; break; } case DISABLE_TYPE_QUEST: { if (!sObjectMgr->GetQuestTemplate(entry)) { handler->PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, entry); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "quest"; break; } case DISABLE_TYPE_MAP: { if (!sMapStore.LookupEntry(entry)) { handler->PSendSysMessage(LANG_COMMAND_NOMAPFOUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "map"; break; } case DISABLE_TYPE_BATTLEGROUND: { if (!sBattlemasterListStore.LookupEntry(entry)) { handler->PSendSysMessage(LANG_COMMAND_NO_BATTLEGROUND_FOUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "battleground"; break; } case DISABLE_TYPE_ACHIEVEMENT_CRITERIA: { if (!sAchievementMgr->GetAchievementCriteria(entry)) { handler->PSendSysMessage(LANG_COMMAND_NO_ACHIEVEMENT_CRITERIA_FOUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "achievement criteria"; break; } case DISABLE_TYPE_OUTDOORPVP: { if (entry > MAX_OUTDOORPVP_TYPES) { handler->PSendSysMessage(LANG_COMMAND_NO_OUTDOOR_PVP_FORUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "outdoorpvp"; break; } case DISABLE_TYPE_VMAP: { if (!sMapStore.LookupEntry(entry)) { handler->PSendSysMessage(LANG_COMMAND_NOMAPFOUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "vmap"; break; } case DISABLE_TYPE_MMAP: { if (!sMapStore.LookupEntry(entry)) { handler->PSendSysMessage(LANG_COMMAND_NOMAPFOUND); handler->SetSentErrorMessage(true); return false; } disableTypeStr = "mmap"; break; } default: break; } PreparedStatement* stmt = NULL; stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_DISABLES); stmt->setUInt32(0, entry); stmt->setUInt8(1, disableType); PreparedQueryResult result = WorldDatabase.Query(stmt); if (result) { handler->PSendSysMessage("This %s (Id: %u) is already disabled.", disableTypeStr.c_str(), entry); handler->SetSentErrorMessage(true); return false; } stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_DISABLES); stmt->setUInt32(0, entry); stmt->setUInt8(1, disableType); stmt->setUInt16(2, flags); stmt->setString(3, disableComment); WorldDatabase.Execute(stmt); handler->PSendSysMessage("Add Disabled %s (Id: %u) for reason %s", disableTypeStr.c_str(), entry, disableComment.c_str()); return true; }
void Corpse::SaveToDB () { // prevent DB data inconsistence problems and duplicates SQLTransaction trans = CharacterDatabase.BeginTransaction(); DeleteFromDB(trans); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_CORPSE); stmt->setUInt32(0, GetGUIDLow()); // corpseGuid stmt->setUInt32(1, GUID_LOPART(GetOwnerGUID())); // guid stmt->setFloat(2, GetPositionX()); // posX stmt->setFloat(3, GetPositionY()); // posY stmt->setFloat(4, GetPositionZ()); // posZ stmt->setFloat(5, GetOrientation()); // orientation stmt->setUInt16(6, GetMapId()); // mapId stmt->setUInt32(7, GetUInt32Value(CORPSE_FIELD_DISPLAY_ID)); // displayId stmt->setString(8, _ConcatFields(CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END)); // itemCache stmt->setUInt32(9, GetUInt32Value(CORPSE_FIELD_BYTES_1)); // bytes1 stmt->setUInt32(10, GetUInt32Value(CORPSE_FIELD_BYTES_2)); // bytes2 stmt->setUInt8(11, GetUInt32Value(CORPSE_FIELD_FLAGS)); // flags stmt->setUInt8(12, GetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS)); // dynFlags stmt->setUInt32(13, uint32(m_time)); // time stmt->setUInt8(14, GetType()); // corpseType stmt->setUInt32(15, GetInstanceId()); // instanceId stmt->setUInt16(16, GetPhaseMask()); // phaseMask trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); }
void Item::SaveToDB(SQLTransaction& trans) { bool isInTransaction = !(trans.null()); if (!isInTransaction) trans = CharacterDatabase.BeginTransaction(); uint32 guid = GetGUIDLow(); switch (uState) { case ITEM_NEW: case ITEM_CHANGED: { uint8 index = 0; PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(uState == ITEM_NEW ? CHAR_ADD_ITEM_INSTANCE : CHAR_UPDATE_ITEM_INSTANCE); stmt->setUInt32( index, GetEntry()); stmt->setUInt32(++index, GUID_LOPART(GetOwnerGUID())); stmt->setUInt32(++index, GUID_LOPART(GetUInt64Value(ITEM_FIELD_CREATOR))); stmt->setUInt32(++index, GUID_LOPART(GetUInt64Value(ITEM_FIELD_GIFTCREATOR))); stmt->setUInt32(++index, GetCount()); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_DURATION)); std::ostringstream ssSpells; for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i) ssSpells << GetSpellCharges(i) << ' '; stmt->setString(++index, ssSpells.str()); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_FLAGS)); std::ostringstream ssEnchants; for (uint8 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i) { ssEnchants << GetEnchantmentId(EnchantmentSlot(i)) << ' '; ssEnchants << GetEnchantmentDuration(EnchantmentSlot(i)) << ' '; ssEnchants << GetEnchantmentCharges(EnchantmentSlot(i)) << ' '; } stmt->setString(++index, ssEnchants.str()); stmt->setInt32 (++index, GetItemRandomPropertyId()); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_DURABILITY)); stmt->setUInt32(++index, GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME)); stmt->setString(++index, m_text); stmt->setUInt32(++index, guid); trans->Append(stmt); if ((uState == ITEM_CHANGED) && HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GIFT_OWNER); stmt->setUInt32(0, GUID_LOPART(GetOwnerGUID())); stmt->setUInt32(1, guid); trans->Append(stmt); } break; } case ITEM_REMOVED: { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); stmt->setUInt32(0, guid); trans->Append(stmt); if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); stmt->setUInt32(0, guid); trans->Append(stmt); } if (!isInTransaction) CharacterDatabase.CommitTransaction(trans); delete this; return; } case ITEM_UNCHANGED: break; } SetState(ITEM_UNCHANGED); if (!isInTransaction) CharacterDatabase.CommitTransaction(trans); }
void WorldSession::HandlePetRename(WorldPacket& recvData) { ObjectGuid petguid; uint8 isdeclined; std::string name; DeclinedName declinedname; recvData >> petguid; recvData >> name; recvData >> isdeclined; Pet* pet = ObjectAccessor::GetPet(*_player, petguid); // check it! if (!pet || !pet->IsPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET || !pet->HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) || pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo()) return; PetNameInvalidReason res = ObjectMgr::CheckPetName(name); if (res != PET_NAME_SUCCESS) { SendPetNameInvalid(res, name, NULL); return; } if (sObjectMgr->IsReservedName(name)) { SendPetNameInvalid(PET_NAME_RESERVED, name, NULL); return; } pet->SetName(name); pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); if (isdeclined) { for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i) { recvData >> declinedname.name[i]; } std::wstring wname; if (!Utf8toWStr(name, wname)) return; if (!ObjectMgr::CheckDeclinedNames(wname, declinedname)) { SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, name, &declinedname); return; } } SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (isdeclined) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME); stmt->setUInt32(0, pet->GetCharmInfo()->GetPetNumber()); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_PET_DECLINEDNAME); stmt->setUInt32(0, pet->GetCharmInfo()->GetPetNumber()); stmt->setUInt64(1, _player->GetGUID().GetCounter()); for (uint8 i = 0; i < 5; i++) stmt->setString(i + 2, declinedname.name[i]); trans->Append(stmt); } PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_NAME); stmt->setString(0, name); stmt->setUInt64(1, _player->GetGUID().GetCounter()); stmt->setUInt32(2, pet->GetCharmInfo()->GetPetNumber()); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped }
/*static*/ void Item::DeleteFromInventoryDB(SQLTransaction& trans, uint32 itemGuid) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM); stmt->setUInt32(0, itemGuid); trans->Append(stmt); }
DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, std::string name, uint32 guid) { uint32 charcount = AccountMgr::GetCharactersCount(account); if (charcount >= 10) return DUMP_TOO_MANY_CHARS; FILE* fin = fopen(file.c_str(), "r"); if (!fin) return DUMP_FILE_OPEN_ERROR; QueryResult result = QueryResult(NULL); char newguid[20], chraccount[20], newpetid[20], currpetid[20], lastpetid[20]; // make sure the same guid doesn't already exist and is safe to use bool incHighest = true; if (guid != 0 && guid < sObjectMgr->_hiCharGuid) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_GUID); stmt->setUInt32(0, guid); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) guid = sObjectMgr->_hiCharGuid; // use first free if exists else incHighest = false; } else guid = sObjectMgr->_hiCharGuid; // normalize the name if specified and check if it exists if (!normalizePlayerName(name)) name = ""; if (ObjectMgr::CheckPlayerName(name, true) == CHAR_NAME_SUCCESS) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) name = ""; // use the one from the dump } else name = ""; // name encoded or empty snprintf(newguid, 20, "%u", guid); snprintf(chraccount, 20, "%u", account); snprintf(newpetid, 20, "%u", sObjectMgr->GeneratePetNumber()); snprintf(lastpetid, 20, "%s", ""); std::map<uint32, uint32> items; std::map<uint32, uint32> mails; char buf[32000] = ""; typedef std::map<uint32, uint32> PetIds; // old->new petid relation typedef PetIds::value_type PetIdsPair; PetIds petids; uint8 gender = GENDER_NONE; uint8 race = RACE_NONE; uint8 playerClass = 0; SQLTransaction trans = CharacterDatabase.BeginTransaction(); while (!feof(fin)) { if (!fgets(buf, 32000, fin)) { if (feof(fin)) break; ROLLBACK(DUMP_FILE_BROKEN); } std::string line; line.assign(buf); // skip empty strings size_t nw_pos = line.find_first_not_of(" \t\n\r\7"); if (nw_pos == std::string::npos) continue; // skip logfile-side dump start notice, the important notes and dump end notices if ((line.substr(nw_pos, 16) == "== START DUMP ==") || (line.substr(nw_pos, 15) == "IMPORTANT NOTE:") || (line.substr(nw_pos, 14) == "== END DUMP ==")) continue; // add required_ check /* if (line.substr(nw_pos, 41) == "UPDATE character_db_version SET required_") { if (!CharacterDatabase.Execute(line.c_str())) ROLLBACK(DUMP_FILE_BROKEN); continue; } */ // determine table name and load type std::string tn = gettablename(line); if (tn.empty()) { sLog->outError("LoadPlayerDump: Can't extract table name from line: '%s'!", line.c_str()); ROLLBACK(DUMP_FILE_BROKEN); } DumpTableType type = DumpTableType(0); uint8 i; for (i = 0; i < DUMP_TABLE_COUNT; ++i) { if (tn == dumpTables[i].name) { type = dumpTables[i].type; break; } } if (i == DUMP_TABLE_COUNT) { sLog->outError("LoadPlayerDump: Unknown table: '%s'!", tn.c_str()); ROLLBACK(DUMP_FILE_BROKEN); } // change the data to server values switch (type) { case DTT_CHARACTER: { if (!changenth(line, 1, newguid)) // characters.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 2, chraccount)) // characters.account update ROLLBACK(DUMP_FILE_BROKEN); race = uint8(atol(getnth(line, 4).c_str())); playerClass = uint8(atol(getnth(line, 5).c_str())); gender = uint8(atol(getnth(line, 6).c_str())); if (name == "") { // check if the original name already exists name = getnth(line, 3); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME); stmt->setString(0, name); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) if (!changenth(line, 37, "1")) // characters.at_login set to "rename on login" ROLLBACK(DUMP_FILE_BROKEN); } else if (!changenth(line, 3, name.c_str())) // characters.name ROLLBACK(DUMP_FILE_BROKEN); const char null[5] = "NULL"; if (!changenth(line, 69, null)) // characters.deleteInfos_Account ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 70, null)) // characters.deleteInfos_Name ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 71, null)) // characters.deleteDate ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_CHAR_TABLE: { if (!changenth(line, 1, newguid)) // character_*.guid update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_EQSET_TABLE: { if (!changenth(line, 1, newguid)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.guid char newSetGuid[24]; snprintf(newSetGuid, 24, UI64FMTD, sObjectMgr->GenerateEquipmentSetGuid()); if (!changenth(line, 2, newSetGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_equipmentsets.setguid break; } case DTT_INVENTORY: { if (!changenth(line, 1, newguid)) // character_inventory.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!changeGuid(line, 2, items, sObjectMgr->_hiItemGuid, true)) ROLLBACK(DUMP_FILE_BROKEN); // character_inventory.bag update if (!changeGuid(line, 4, items, sObjectMgr->_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_inventory.item update break; } case DTT_MAIL: // mail { if (!changeGuid(line, 1, mails, sObjectMgr->_mailId)) ROLLBACK(DUMP_FILE_BROKEN); // mail.id update if (!changenth(line, 6, newguid)) // mail.receiver update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_MAIL_ITEM: // mail_items { if (!changeGuid(line, 1, mails, sObjectMgr->_mailId)) ROLLBACK(DUMP_FILE_BROKEN); // mail_items.id if (!changeGuid(line, 2, items, sObjectMgr->_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // mail_items.item_guid if (!changenth(line, 3, newguid)) // mail_items.receiver ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_ITEM: { // item, owner, data field:item, owner guid if (!changeGuid(line, 1, items, sObjectMgr->_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // item_instance.guid update if (!changenth(line, 3, newguid)) // item_instance.owner_guid update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_ITEM_GIFT: { if (!changenth(line, 1, newguid)) // character_gifts.guid update ROLLBACK(DUMP_FILE_BROKEN); if (!changeGuid(line, 2, items, sObjectMgr->_hiItemGuid)) ROLLBACK(DUMP_FILE_BROKEN); // character_gifts.item_guid update break; } case DTT_PET: { //store a map of old pet id to new inserted pet id for use by type 5 tables snprintf(currpetid, 20, "%s", getnth(line, 1).c_str()); if (*lastpetid == '\0') snprintf(lastpetid, 20, "%s", currpetid); if (strcmp(lastpetid, currpetid) != 0) { snprintf(newpetid, 20, "%d", sObjectMgr->GeneratePetNumber()); snprintf(lastpetid, 20, "%s", currpetid); } std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid)); if (petids_iter == petids.end()) { petids.insert(PetIdsPair(atoi(currpetid), atoi(newpetid))); } if (!changenth(line, 1, newpetid)) // character_pet.id update ROLLBACK(DUMP_FILE_BROKEN); if (!changenth(line, 3, newguid)) // character_pet.owner update ROLLBACK(DUMP_FILE_BROKEN); break; } case DTT_PET_TABLE: // pet_aura, pet_spell, pet_spell_cooldown { snprintf(currpetid, 20, "%s", getnth(line, 1).c_str()); // lookup currpetid and match to new inserted pet id std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid)); if (petids_iter == petids.end()) // couldn't find new inserted id ROLLBACK(DUMP_FILE_BROKEN); snprintf(newpetid, 20, "%d", petids_iter->second); if (!changenth(line, 1, newpetid)) ROLLBACK(DUMP_FILE_BROKEN); break; } default: sLog->outError("Unknown dump table type: %u", type); break; } fixNULLfields(line); trans->Append(line.c_str()); } CharacterDatabase.CommitTransaction(trans); // in case of name conflict player has to rename at login anyway sWorld->AddCharacterNameData(guid, name, gender, race, playerClass); sObjectMgr->_hiItemGuid += items.size(); sObjectMgr->_mailId += mails.size(); if (incHighest) ++sObjectMgr->_hiCharGuid; fclose(fin); return DUMP_SUCCESS; }
void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) { if (packet.Info.Attachments.size() > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); return; } if (!CanOpenMailBox(packet.Info.Mailbox)) return; if (packet.Info.Target.empty()) return; Player* player = _player; if (player->getLevel() < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_SENDER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } ObjectGuid receiverGuid; if (normalizePlayerName(packet.Info.Target)) receiverGuid = ObjectMgr::GetPlayerGUIDByName(packet.Info.Target); if (!receiverGuid) { TC_LOG_INFO("network", "Player %s is sending mail to %s (GUID: not existed!) with subject %s " "and body %s includes " SZFMTD " items, " SI64FMTD " copper and " SI64FMTD " COD copper with StationeryID = %d, PackageID = %d", GetPlayerInfo().c_str(), packet.Info.Target.c_str(), packet.Info.Subject.c_str(), packet.Info.Body.c_str(), packet.Info.Attachments.size(), packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID, packet.Info.PackageID); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } if (packet.Info.SendMoney < 0) { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative money value (SendMoney: " SI64FMTD ")", GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.SendMoney); return; } if (packet.Info.Cod < 0) { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative COD value (Cod: " SI64FMTD ")", GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.Cod); return; } TC_LOG_INFO("network", "Player %s is sending mail to %s (%s) with subject %s and body %s " "includes " SZFMTD " items, " SI64FMTD " copper and " SI64FMTD " COD copper with StationeryID = %d, PackageID = %d", GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.Subject.c_str(), packet.Info.Body.c_str(), packet.Info.Attachments.size(), packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID, packet.Info.PackageID); if (player->GetGUID() == receiverGuid) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; } uint32 cost = !packet.Info.Attachments.empty() ? 30 * packet.Info.Attachments.size() : 30; // price hardcoded in client int64 reqmoney = cost + packet.Info.SendMoney; // Check for overflow if (reqmoney < packet.Info.SendMoney) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } if (!player->HasEnoughMoney(reqmoney) && !player->IsGameMaster()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; } Player* receiver = ObjectAccessor::FindConnectedPlayer(receiverGuid); uint32 receiverTeam = 0; uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails uint8 receiverLevel = 0; uint32 receiverAccountId = 0; uint32 receiverBnetAccountId = 0; if (receiver) { receiverTeam = receiver->GetTeam(); mailsCount = receiver->GetMailSize(); receiverLevel = receiver->getLevel(); receiverAccountId = receiver->GetSession()->GetAccountId(); receiverBnetAccountId = receiver->GetSession()->GetBattlenetAccountId(); } else { receiverTeam = ObjectMgr::GetPlayerTeamByGUID(receiverGuid); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); stmt->setUInt64(0, receiverGuid.GetCounter()); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); mailsCount = fields[0].GetUInt64(); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); stmt->setUInt64(0, receiverGuid.GetCounter()); result = CharacterDatabase.Query(stmt); if (result) { Field* fields = result->Fetch(); receiverLevel = fields[0].GetUInt8(); } receiverAccountId = ObjectMgr::GetPlayerAccountIdByGUID(receiverGuid); receiverBnetAccountId = Battlenet::AccountMgr::GetIdByGameAccount(receiverAccountId); } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. if (mailsCount > 100) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } // test the receiver's Faction... or all items are account bound bool accountBound = !packet.Info.Attachments.empty(); for (auto const& att : packet.Info.Attachments) { if (Item* item = player->GetItemByGuid(att.ItemGUID)) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->GetFlags() & ITEM_FLAG_BIND_TO_ACCOUNT)) { accountBound = false; break; } } } if (!accountBound && player->GetTeam() != receiverTeam && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_MAIL)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } if (receiverLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } std::vector<Item*> items; for (auto const& att : packet.Info.Attachments) { if (att.ItemGUID.IsEmpty()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); 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, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } if (!item->CanBeTraded(true)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { if (!item->IsBattlenetAccountBound() || !player->GetSession()->GetBattlenetAccountId() || player->GetSession()->GetBattlenetAccountId() != receiverBnetAccountId) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_NOT_SAME_ACCOUNT); return; } } if (item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } if (packet.Info.Cod && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } if (item->IsNotEmptyBag()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_DESTROY_NONEMPTY_BAG); return; } items.push_back(item); } player->SendMailResult(0, MAIL_SEND, MAIL_OK); player->ModifyMoney(-reqmoney); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; MailDraft draft(packet.Info.Subject, packet.Info.Body); SQLTransaction trans = CharacterDatabase.BeginTransaction(); if (!packet.Info.Attachments.empty() || packet.Info.SendMoney > 0) { bool log = HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE); if (!packet.Info.Attachments.empty()) { for (auto const& item : items) { if (log) { sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail item: %s (Entry: %u Count: %u) " "to: %s (%s) (Account: %u)", GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), 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->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) { sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail money: " SI64FMTD " to: %s (%s) (Account: %u)", GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), packet.Info.SendMoney, packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } } // If theres is an item, there is a one hour delivery delay if sent to another account's character. uint32 deliver_delay = needItemDelay ? sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY) : 0; // Mail sent between guild members arrives instantly if they have the guild perk "Guild Mail" if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) if (guild->GetLevel() >= 17 && 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(packet.Info.SendMoney) .AddCOD(packet.Info.Cod) .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), packet.Info.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); }
uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result, uint8 asynchLoadType) { if (!GetPlayer() || GetPlayer()->GetPet() || GetPlayer()->GetVehicle() || GetPlayer()->IsSpectator()) return PET_LOAD_ERROR; if (!result) return PET_LOAD_NO_RESULT; Field* fields = result->Fetch(); // Xinef: this can happen if fetch is called twice, impossibru. if (!fields) return PET_LOAD_ERROR; Player* owner = GetPlayer(); // update for case of current pet "slot = 0" uint32 petentry = fields[1].GetUInt32(); if (!petentry) return PET_LOAD_NO_RESULT; uint8 petSlot = fields[7].GetUInt8(); bool current = petSlot == PET_SAVE_AS_CURRENT; uint32 summon_spell_id = fields[15].GetUInt32(); SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summon_spell_id); // CANT BE NULL bool is_temporary_summoned = spellInfo && spellInfo->GetDuration() > 0; uint32 pet_number = fields[0].GetUInt32(); uint32 savedhealth = fields[10].GetUInt32(); uint32 savedmana = fields[11].GetUInt32(); PetType pet_type = PetType(fields[16].GetUInt8()); // xinef: BG resurrect, overwrite saved value if (asynchLoadType == PET_LOAD_BG_RESURRECT) savedhealth = 1; if (pet_type == HUNTER_PET && savedhealth == 0 && asynchLoadType != PET_LOAD_SUMMON_DEAD_PET) { WorldPacket data(SMSG_CAST_FAILED, 1+4+1+4); data << uint8(0); data << uint32(883); data << uint8(SPELL_FAILED_TARGETS_DEAD); SendPacket(&data); owner->RemoveSpellCooldown(883, false); return PET_LOAD_ERROR; } // check temporary summoned pets like mage water elemental if (current && is_temporary_summoned) return PET_LOAD_ERROR; if (pet_type == HUNTER_PET) { CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petentry); if (!creatureInfo || !creatureInfo->IsTameable(owner->CanTameExoticPets())) return PET_LOAD_ERROR; } Map* map = owner->GetMap(); uint32 guid = sObjectMgr->GenerateLowGuid(HIGHGUID_PET); Pet* pet = new Pet(owner, pet_type); LoadPetFromDBQueryHolder* holder = new LoadPetFromDBQueryHolder(pet_number, current, uint32(time(NULL) - fields[14].GetUInt32()), fields[13].GetString(), savedhealth, savedmana); if (!pet->Create(guid, map, owner->GetPhaseMask(), petentry, pet_number) || !holder->Initialize()) { delete pet; delete holder; return PET_LOAD_ERROR; } float px, py, pz; owner->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle()); if (!pet->IsPositionValid()) { sLog->outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)", pet->GetGUIDLow(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY()); delete pet; delete holder; return PET_LOAD_ERROR; } pet->SetLoading(true); pet->Relocate(px, py, pz, owner->GetOrientation()); pet->setPetType(pet_type); pet->setFaction(owner->getFaction()); pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id); if (pet->IsCritter()) { map->AddToMap(pet->ToCreature(), true); pet->SetLoading(false); // xinef, mine delete holder; return PET_LOAD_OK; } pet->GetCharmInfo()->SetPetNumber(pet_number, pet->IsPermanentPetFor(owner)); pet->SetDisplayId(fields[3].GetUInt32()); pet->SetNativeDisplayId(fields[3].GetUInt32()); uint32 petlevel = fields[4].GetUInt8(); pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); pet->SetName(fields[8].GetString()); switch (pet->getPetType()) { case SUMMON_PET: petlevel = owner->getLevel(); if (pet->IsPetGhoul()) pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x400); // class = rogue else pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet dismiss, cancel) break; case HUNTER_PET: pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus pet->SetSheath(SHEATH_STATE_MELEE); pet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED); pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); // this enables popup window (pet abandon, cancel) pet->SetMaxPower(POWER_HAPPINESS, pet->GetCreatePowers(POWER_HAPPINESS)); pet->SetPower(POWER_HAPPINESS, fields[12].GetUInt32()); pet->setPowerType(POWER_FOCUS); break; default: if (!pet->IsPetGhoul()) sLog->outError("Pet have incorrect type (%u) for pet loading.", pet->getPetType()); break; } pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped here pet->SetCreatorGUID(owner->GetGUID()); owner->SetMinion(pet, true); pet->InitStatsForLevel(petlevel); pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32()); pet->SynchronizeLevelWithOwner(); pet->SetReactState(ReactStates(fields[6].GetUInt8())); pet->SetCanModifyStats(true); // set current pet as current // 0=current // 1..MAX_PET_STABLES in stable slot // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning)) if (petSlot) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID); stmt->setUInt8(0, uint8(PET_SAVE_NOT_IN_SLOT)); stmt->setUInt32(1, owner->GetGUIDLow()); stmt->setUInt8(2, uint8(PET_SAVE_AS_CURRENT)); stmt->setUInt32(3, pet_number); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID); stmt->setUInt8(0, uint8(PET_SAVE_AS_CURRENT)); stmt->setUInt32(1, owner->GetGUIDLow()); stmt->setUInt32(2, pet_number); trans->Append(stmt); CharacterDatabase.CommitTransaction(trans); } // Send fake summon spell cast - this is needed for correct cooldown application for spells // Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside // TODO: pets should be summoned from real cast instead of just faking it? if (summon_spell_id) { WorldPacket data(SMSG_SPELL_GO, (8+8+4+4+2)); data.append(owner->GetPackGUID()); data.append(owner->GetPackGUID()); data << uint8(0); data << uint32(summon_spell_id); data << uint32(256); // CAST_FLAG_UNKNOWN3 data << uint32(0); owner->SendMessageToSet(&data, true); } // do it as early as possible! pet->InitTalentForLevel(); // set original talents points before spell loading if (!is_temporary_summoned) pet->GetCharmInfo()->InitPetActionBar(); map->AddToMap(pet->ToCreature(), true); if (pet->getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA)); else { pet->SetHealth(savedhealth > pet->GetMaxHealth() ? pet->GetMaxHealth() : savedhealth); pet->SetPower(POWER_MANA, savedmana > pet->GetMaxPower(POWER_MANA) ? pet->GetMaxPower(POWER_MANA) : savedmana); } pet->SetAsynchLoadType(asynchLoadType); // xinef: clear any old result if (_loadPetFromDBSecondCallback.ready()) { SQLQueryHolder* param; _loadPetFromDBSecondCallback.get(param); delete param; } _loadPetFromDBSecondCallback.cancel(); _loadPetFromDBSecondCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder); return PET_LOAD_OK; }