diff options
| author | Nay <dnpd.dd@gmail.com> | 2012-07-30 16:39:46 +0100 |
|---|---|---|
| committer | Nay <dnpd.dd@gmail.com> | 2012-07-30 16:39:46 +0100 |
| commit | c24de2c6d8883a9c4541003c259196c830de2add (patch) | |
| tree | 677ee37797e9cbbef028c210e06ad802cef95f83 | |
| parent | 195e0369cff80fb89afb267ce479bdd2e9a4e31b (diff) | |
Core: Implement Void Storage
| -rw-r--r-- | sql/base/characters_database.sql | 30 | ||||
| -rw-r--r-- | sql/updates/characters/2012_07_30_00_characters_void_storage_434.sql | 11 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.cpp | 190 | ||||
| -rwxr-xr-x | src/server/game/Entities/Player/Player.h | 41 | ||||
| -rwxr-xr-x | src/server/game/Entities/Unit/Unit.h | 2 | ||||
| -rwxr-xr-x | src/server/game/Globals/ObjectMgr.cpp | 11 | ||||
| -rwxr-xr-x | src/server/game/Globals/ObjectMgr.h | 2 | ||||
| -rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Handlers/VoidStorageHandler.cpp | 618 | ||||
| -rwxr-xr-x | src/server/game/Miscellaneous/SharedDefines.h | 20 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 21 | ||||
| -rwxr-xr-x | src/server/game/Server/Protocol/Opcodes.h | 6 | ||||
| -rwxr-xr-x | src/server/game/Server/WorldSession.h | 7 | ||||
| -rwxr-xr-x | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
| -rwxr-xr-x | src/server/shared/Database/Implementation/CharacterDatabase.h | 4 |
15 files changed, 956 insertions, 15 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 8c3913bda73..f42c8f2e6ad 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -2266,6 +2266,34 @@ LOCK TABLES `reserved_name` WRITE; UNLOCK TABLES; -- +-- Table structure for table `void_storage` +-- + +DROP TABLE IF EXISTS `void_storage`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `void_storage` ( + `itemId` bigint(20) unsigned NOT NULL, + `playerGuid` int(10) unsigned NOT NULL, + `itemEntry` mediumint(8) unsigned NOT NULL, + `slot` tinyint(3) unsigned NOT NULL, + `creatorGuid` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`itemId`), + UNIQUE KEY `idx_player_slot` (`playerGuid`,`slot`), + KEY `idx_player` (`playerGuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `void_storage` +-- + +LOCK TABLES `void_storage` WRITE; +/*!40000 ALTER TABLE `void_storage` DISABLE KEYS */; +/*!40000 ALTER TABLE `void_storage` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `warden_action` -- @@ -2322,4 +2350,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2012-05-30 12:56:18 +-- Dump completed on 2012-07-30 16:34:12 diff --git a/sql/updates/characters/2012_07_30_00_characters_void_storage_434.sql b/sql/updates/characters/2012_07_30_00_characters_void_storage_434.sql new file mode 100644 index 00000000000..e8a47c5f91c --- /dev/null +++ b/sql/updates/characters/2012_07_30_00_characters_void_storage_434.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS `void_storage`; +CREATE TABLE IF NOT EXISTS `void_storage` ( + `itemId` bigint(20) unsigned NOT NULL, + `playerGuid` int(10) unsigned NOT NULL, + `itemEntry` mediumint(8) unsigned NOT NULL, + `slot` tinyint(3) unsigned NOT NULL, + `creatorGuid` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`itemId`), + UNIQUE KEY `idx_player_slot` (`playerGuid`,`slot`), + KEY `idx_player` (`playerGuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 56c3915bd65..6cdea51bfb3 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -714,7 +714,7 @@ Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_rep m_DailyQuestChanged = false; m_lastDailyQuestTime = 0; - for (uint8 i=0; i<MAX_TIMERS; i++) + for (uint8 i=0; i < MAX_TIMERS; i++) m_MirrorTimer[i] = DISABLED_MIRROR_TIMER; m_MirrorTimerFlags = UNDERWATER_NONE; @@ -730,7 +730,7 @@ Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_rep for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j) { - m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; + m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; m_bgBattlegroundQueueID[j].invitedToInstance = 0; } @@ -842,6 +842,8 @@ Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_rep m_SeasonalQuestChanged = false; SetPendingBind(0, 0); + + memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*)); } Player::~Player() @@ -873,6 +875,9 @@ Player::~Player() delete m_declinedname; delete m_runes; + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + delete _voidStorageItems[i]; + sWorld->DecreasePlayerCount(); } @@ -17195,6 +17200,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff); + if (IsVoidStorageUnlocked()) + _LoadVoidStorage(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADVOIDSTORAGE)); + // update items with duration and realtime UpdateItemDuration(time_diff, true); @@ -17654,6 +17662,50 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) _ApplyAllItemMods(); } +void Player::_LoadVoidStorage(PreparedQueryResult result) +{ + if (!result) + return; + + do + { + // SELECT itemid, itemEntry, slot, creatorGuid FROM void_storage WHERE playerGuid = ? + Field* fields = result->Fetch(); + + uint64 itemId = fields[0].GetUInt64(); + uint32 itemEntry = fields[1].GetUInt32(); + uint8 slot = fields[2].GetUInt8(); + uint32 creatorGuid = fields[3].GetUInt32(); + + if (!itemId) + { + sLog->outError("Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid id (item id: %u, entry: %u).", GetGUIDLow(), GetName(), itemId, itemEntry); + continue; + } + + if (!sObjectMgr->GetItemTemplate(itemEntry)) + { + sLog->outError("Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid entry (item id: %u, entry: %u).", GetGUIDLow(), GetName(), itemId, itemEntry); + continue; + } + + if (slot < 0 || slot > VOID_STORAGE_MAX_SLOT) + { + sLog->outError("Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid slot (item id: %u, entry: %u, slot: %u).", GetGUIDLow(), GetName(), itemId, itemEntry, slot); + continue; + } + + if (!sObjectMgr->GetPlayerByLowGUID(creatorGuid)) + { + sLog->outError("Player::_LoadVoidStorage - Player (GUID: %u, name: %s) has an item with an invalid creator guid, set to 0 (item id: %u, entry: %u, creatorGuid: %u).", GetGUIDLow(), GetName(), itemId, itemEntry, creatorGuid); + creatorGuid = 0; + } + + _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid); + } + while (result->NextRow()); +} + Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, Field* fields) { PreparedStatement* stmt = NULL; @@ -18882,6 +18934,7 @@ void Player::SaveToDB(bool create /*=false*/) _SaveBGData(trans); _SaveInventory(trans); + _SaveVoidStorage(trans); _SaveQuestStatus(trans); _SaveDailyQuestStatus(trans); _SaveWeeklyQuestStatus(trans); @@ -19121,7 +19174,7 @@ void Player::_SaveInventory(SQLTransaction& trans) // save all changes to the item... if (item->GetState() != ITEM_NEW) // only for existing items, no dupes item->SaveToDB(trans); - // ...but do not save position in invntory + // ...but do not save position in inventory continue; } } @@ -19151,6 +19204,35 @@ void Player::_SaveInventory(SQLTransaction& trans) m_itemUpdateQueue.clear(); } +void Player::_SaveVoidStorage(SQLTransaction& trans) +{ + PreparedStatement* stmt = NULL; + uint32 lowGuid = GetGUIDLow(); + + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + { + if (!_voidStorageItems[i]) // unused item + { + // DELETE FROM void_Storage WHERE slot = ? AND playerGuid = ? + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_VOID_STORAGE_ITEM_BY_SLOT); + stmt->setUInt8(0, i); + stmt->setUInt32(1, lowGuid); + } + else + { + // REPLACE INTO character_inventory (itemId, playerGuid, itemEntry, slot, creatorGuid) VALUES (?, ?, ?, ?, ?) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_VOID_STORAGE_ITEM); + stmt->setUInt64(0, _voidStorageItems[i]->ItemId); + stmt->setUInt32(1, lowGuid); + stmt->setUInt32(2, _voidStorageItems[i]->ItemEntry); + stmt->setUInt8(3, i); + stmt->setUInt32(4, _voidStorageItems[i]->CreatorGuid); + } + + trans->Append(stmt); + } +} + void Player::_SaveMail(SQLTransaction& trans) { if (!m_mailsLoaded) @@ -25602,6 +25684,108 @@ bool Player::IsInWhisperWhiteList(uint64 guid) return false; } +uint8 Player::GetNextVoidStorageFreeSlot() const +{ + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + if (!_voidStorageItems[i]) // unused item + return i; + + return -1; +} + +uint8 Player::GetNumOfVoidStorageFreeSlots() const +{ + uint8 count = 0; + + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + if (!_voidStorageItems[i]) + count++; + + return count; +} + +uint8 Player::AddVoidStorageItem(const VoidStorageItem& item) +{ + uint8 slot = GetNextVoidStorageFreeSlot(); + + if (slot < 0 || slot > VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); + return -1; + } + + _voidStorageItems[slot] = new VoidStorageItem(item.ItemId, item.ItemEntry, item.CreatorGuid); + return slot; +} + +void Player::AddVoidStorageItemAtSlot(uint8 slot, const VoidStorageItem& item) +{ + if (slot < 0 || slot > VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); + return; + } + + if (_voidStorageItems[slot]) + { + sLog->outError("Player::AddVoidStorageItemAtSlot - Player (GUID: %u, name: %s) tried to add an item to an used slot (item id: %u, entry: %u, slot: %u).", GetGUIDLow(), GetName(), _voidStorageItems[slot]->ItemId, _voidStorageItems[slot]->ItemEntry, slot); + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return; + } + + _voidStorageItems[slot] = new VoidStorageItem(item.ItemId, item.ItemId, item.CreatorGuid); +} + +void Player::DeleteVoidStorageItem(uint8 slot) +{ + if (slot < 0 || slot > VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return; + } + + delete _voidStorageItems[slot]; + _voidStorageItems[slot] = NULL; +} + +bool Player::SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot) +{ + if (oldSlot < 0 || oldSlot > VOID_STORAGE_MAX_SLOT || newSlot < 0 || newSlot > VOID_STORAGE_MAX_SLOT || oldSlot == newSlot) + { + + return false; + } + + // verify + std::swap(_voidStorageItems[newSlot], _voidStorageItems[oldSlot]); + return true; +} + +VoidStorageItem* Player::GetVoidStorageItem(uint8 slot) const +{ + if (slot < 0 || slot > VOID_STORAGE_MAX_SLOT) + { + GetSession()->SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return NULL; + } + + return _voidStorageItems[slot]; +} + +VoidStorageItem* Player::GetVoidStorageItem(uint64 id, uint8& slot) const +{ + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + { + if (_voidStorageItems[i] && _voidStorageItems[i]->ItemId == id) + { + slot = i; + return _voidStorageItems[i]; + } + } + + return NULL; +} + bool Player::SetHover(bool enable) { if (!Unit::SetHover(enable)) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index aba570c1d37..6b8686a7c0e 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -405,7 +405,7 @@ enum PlayerFlags PLAYER_FLAGS_UNK26 = 0x04000000, PLAYER_FLAGS_UNK27 = 0x08000000, PLAYER_FLAGS_UNK28 = 0x10000000, - PLAYER_FLAGS_UNK29 = 0x20000000, + PLAYER_FLAGS_VOID_UNLOCKED = 0x20000000, // void storage PLAYER_FLAGS_UNK30 = 0x40000000, PLAYER_FLAGS_UNK31 = 0x80000000, }; @@ -816,6 +816,7 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW = 29, PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES = 30, PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS = 31, + PLAYER_LOGIN_QUERY_LOADVOIDSTORAGE = 32, MAX_PLAYER_LOGIN_QUERY, }; @@ -979,6 +980,27 @@ struct BGData bool HasTaxiPath() const { return taxiPath[0] && taxiPath[1]; } }; +struct VoidStorageItem +{ + VoidStorageItem() + { + ItemId = 0; + ItemEntry = 0; + CreatorGuid = 0; + } + + VoidStorageItem(uint64 id, uint32 entry, uint32 creator) + { + ItemId = id; + ItemEntry = entry; + CreatorGuid = creator; + } + + uint64 ItemId; + uint32 ItemEntry; + uint32 CreatorGuid; +}; + class TradeData { public: // constructors @@ -2589,6 +2611,19 @@ class Player : public Unit, public GridObject<Player> } } + // Void Storage + bool IsVoidStorageUnlocked() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + void UnlockVoidStorage() { SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + void LockVoidStorage() { RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_VOID_UNLOCKED); } + uint8 GetNextVoidStorageFreeSlot() const; + uint8 GetNumOfVoidStorageFreeSlots() const; + uint8 AddVoidStorageItem(const VoidStorageItem& item); + void AddVoidStorageItemAtSlot(uint8 slot, const VoidStorageItem& item); + void DeleteVoidStorageItem(uint8 slot); + bool SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot); + VoidStorageItem* GetVoidStorageItem(uint8 slot) const; + VoidStorageItem* GetVoidStorageItem(uint64 id, uint8& slot) const; + protected: // Gamemaster whisper whitelist WhisperListContainer WhisperList; @@ -2638,6 +2673,7 @@ class Player : public Unit, public GridObject<Player> void _LoadGlyphAuras(); void _LoadBoundInstances(PreparedQueryResult result); void _LoadInventory(PreparedQueryResult result, uint32 timeDiff); + void _LoadVoidStorage(PreparedQueryResult result); void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery); void _LoadMail(); void _LoadMailedItems(Mail* mail); @@ -2667,6 +2703,7 @@ class Player : public Unit, public GridObject<Player> void _SaveActions(SQLTransaction& trans); void _SaveAuras(SQLTransaction& trans); void _SaveInventory(SQLTransaction& trans); + void _SaveVoidStorage(SQLTransaction& trans); void _SaveMail(SQLTransaction& trans); void _SaveQuestStatus(SQLTransaction& trans); void _SaveDailyQuestStatus(SQLTransaction& trans); @@ -2714,6 +2751,8 @@ class Player : public Unit, public GridObject<Player> PlayerCurrenciesMap m_currencies; uint32 _GetCurrencyWeekCap(const CurrencyTypesEntry* currency) const; + VoidStorageItem* _voidStorageItems[VOID_STORAGE_MAX_SLOT]; + std::vector<Item*> m_itemUpdateQueue; bool m_itemUpdateQueueBlocked; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 7984c91bbd3..a010a119017 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -661,6 +661,8 @@ enum NPCFlags UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click) UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x02000000, // players with mounts that have vehicle data should have it set + UNIT_NPC_FLAG_REFORGER = 0x08000000, // reforging + UNIT_NPC_FLAG_VAULTKEEPER = 0x20000000, // void storage }; enum MovementFlags diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 79e29ff2761..258e5d3ec25 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -233,7 +233,7 @@ bool SpellClickInfo::IsFitToRequirements(Unit const* clicker, Unit const* clicke ObjectMgr::ObjectMgr(): _auctionId(1), _equipmentSetGuid(1), _itemTextId(1), _mailId(1), _hiPetNumber(1), _hiCharGuid(1), _hiCreatureGuid(1), _hiPetGuid(1), _hiVehicleGuid(1), _hiItemGuid(1), - _hiGoGuid(1), _hiDoGuid(1), _hiCorpseGuid(1), _hiMoTransGuid(1) + _hiGoGuid(1), _hiDoGuid(1), _hiCorpseGuid(1), _hiMoTransGuid(1), _voidItemId(1) {} ObjectMgr::~ObjectMgr() @@ -6315,6 +6315,10 @@ void ObjectMgr::SetHighestGuids() result = CharacterDatabase.Query("SELECT MAX(guid) FROM groups"); if (result) sGroupMgr->SetGroupDbStoreSize((*result)[0].GetUInt32()+1); + + result = CharacterDatabase.Query("SELECT MAX(itemId) from void_storage"); + if (result) + _voidItemId = (*result)[0].GetUInt64()+1; } uint32 ObjectMgr::GenerateAuctionID() @@ -6797,6 +6801,11 @@ uint32 ObjectMgr::GeneratePetNumber() return ++_hiPetNumber; } +uint64 ObjectMgr::GenerateVoidStorageItemId() +{ + return ++_voidItemId; +} + void ObjectMgr::LoadCorpses() { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index b1ee342a0e7..a13108bd7f3 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -941,6 +941,7 @@ class ObjectMgr uint64 GenerateEquipmentSetGuid(); uint32 GenerateMailID(); uint32 GeneratePetNumber(); + uint64 GenerateVoidStorageItemId(); typedef std::multimap<int32, uint32> ExclusiveQuestGroups; ExclusiveQuestGroups mExclusiveQuestGroups; @@ -1176,6 +1177,7 @@ class ObjectMgr uint32 _itemTextId; uint32 _mailId; uint32 _hiPetNumber; + uint64 _voidItemId; // first free low guid for selected guid type uint32 _hiCharGuid; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 01668314c63..d75d25b00e2 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -110,6 +110,10 @@ bool LoginQueryHolder::Initialize() stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_VOID_STORAGE); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADVOIDSTORAGE, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS); stmt->setUInt32(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, stmt); diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp new file mode 100644 index 00000000000..0a0cc32e535 --- /dev/null +++ b/src/server/game/Handlers/VoidStorageHandler.cpp @@ -0,0 +1,618 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Common.h" +#include "WorldPacket.h" +#include "WorldSession.h" +#include "World.h" +#include "ObjectAccessor.h" +#include "Log.h" +#include "Opcodes.h" +#include "Player.h" +#include <list> +#include <vector> +#include <utility> + +void WorldSession::SendVoidStorageTransferResult(VoidTransferError result) +{ + WorldPacket data(SMSG_VOID_TRANSFER_RESULT, 4); + data << uint32(result); + SendPacket(&data); +} + +void WorldSession::HandleVoidStorageUnlock(WorldPacket& recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_VOID_STORAGE_UNLOCK"); + Player* player = GetPlayer(); + + ObjectGuid npcGuid; + npcGuid[4] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[2] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[7] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[0]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(npcGuid[4]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageUnlock - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (player->IsVoidStorageUnlocked()) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageUnlock - Player (GUID: %u, name: %s) tried to unlock void storage a 2nd time.", player->GetGUIDLow(), player->GetName()); + return; + } + + player->ModifyMoney(-int64(VOID_STORAGE_UNLOCK)); + player->UnlockVoidStorage(); +} + +void WorldSession::HandleVoidStorageQuery(WorldPacket& recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_VOID_STORAGE_QUERY"); + Player* player = GetPlayer(); + + ObjectGuid npcGuid; + npcGuid[4] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[7] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[2] = recvData.ReadBit(); + + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[0]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(npcGuid[2]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageQuery - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (!player->IsVoidStorageUnlocked()) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageQuery - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName()); + return; + } + + uint8 count = 0; + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + if (player->GetVoidStorageItem(i)) + ++count; + + WorldPacket data(SMSG_VOID_STORAGE_CONTENTS, 2 * count + (14 + 4 + 4 + 4 + 4) * count); + + data.WriteBits(count, 8); + + ByteBuffer itemData((14 + 4 + 4 + 4 + 4) * count); + + for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) + { + VoidStorageItem* item = player->GetVoidStorageItem(i); + if (!item) + continue; + + ObjectGuid itemId = item->ItemId; + ObjectGuid creatorGuid = item->CreatorGuid; + + data.WriteBit(creatorGuid[3]); + data.WriteBit(itemId[5]); + data.WriteBit(creatorGuid[6]); + data.WriteBit(creatorGuid[1]); + data.WriteBit(itemId[1]); + data.WriteBit(itemId[3]); + data.WriteBit(itemId[6]); + data.WriteBit(creatorGuid[5]); + data.WriteBit(creatorGuid[2]); + data.WriteBit(itemId[2]); + data.WriteBit(creatorGuid[4]); + data.WriteBit(itemId[0]); + data.WriteBit(itemId[4]); + data.WriteBit(itemId[7]); + data.WriteBit(creatorGuid[0]); + data.WriteBit(creatorGuid[7]); + + itemData.WriteByteSeq(creatorGuid[3]); + + itemData << int32(0); // unk, SuffixFactor? large ints, both positive and negative appear here + + itemData.WriteByteSeq(creatorGuid[4]); + + itemData << uint32(i); + + itemData.WriteByteSeq(itemId[0]); + itemData.WriteByteSeq(itemId[6]); + itemData.WriteByteSeq(creatorGuid[0]); + + itemData << int32(0); // unk, usually 0, not always + + itemData.WriteByteSeq(itemId[4]); + itemData.WriteByteSeq(itemId[5]); + itemData.WriteByteSeq(itemId[2]); + itemData.WriteByteSeq(creatorGuid[2]); + itemData.WriteByteSeq(creatorGuid[6]); + itemData.WriteByteSeq(itemId[1]); + itemData.WriteByteSeq(itemId[3]); + itemData.WriteByteSeq(creatorGuid[5]); + itemData.WriteByteSeq(creatorGuid[7]); + + itemData << uint32(item->ItemEntry); + + itemData.WriteByteSeq(itemId[7]); + } + + data.FlushBits(); + data.append(itemData); + + SendPacket(&data); +} + +void WorldSession::HandleVoidStorageTransfer(WorldPacket& recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_VOID_STORAGE_TRANSFER"); + Player* player = GetPlayer(); + + // Read everything + + ObjectGuid npcGuid; + npcGuid[1] = recvData.ReadBit(); + + uint32 countDeposit = recvData.ReadBits(26); + + if (countDeposit > 9) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to deposit more than 9 items (%u).", player->GetGUIDLow(), player->GetName(), countDeposit); + return; + } + + std::vector<ObjectGuid> itemGuids(countDeposit); + for (uint32 i = 0; i < countDeposit; ++i) + { + itemGuids[i][4] = recvData.ReadBit(); + itemGuids[i][6] = recvData.ReadBit(); + itemGuids[i][7] = recvData.ReadBit(); + itemGuids[i][0] = recvData.ReadBit(); + itemGuids[i][1] = recvData.ReadBit(); + itemGuids[i][5] = recvData.ReadBit(); + itemGuids[i][3] = recvData.ReadBit(); + itemGuids[i][2] = recvData.ReadBit(); + } + + npcGuid[2] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[4] = recvData.ReadBit(); + + uint32 countWithdraw = recvData.ReadBits(26); + + if (countWithdraw > 9) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to withdraw more than 9 items (%u).", player->GetGUIDLow(), player->GetName(), countWithdraw); + return; + } + + std::vector<ObjectGuid> itemIds(countWithdraw); + for (uint32 i = 0; i < countWithdraw; ++i) + { + itemIds[i][4] = recvData.ReadBit(); + itemIds[i][7] = recvData.ReadBit(); + itemIds[i][1] = recvData.ReadBit(); + itemIds[i][0] = recvData.ReadBit(); + itemIds[i][2] = recvData.ReadBit(); + itemIds[i][3] = recvData.ReadBit(); + itemIds[i][5] = recvData.ReadBit(); + itemIds[i][6] = recvData.ReadBit(); + } + + npcGuid[7] = recvData.ReadBit(); + + recvData.FlushBits(); + + for (uint32 i = 0; i < countDeposit; ++i) + { + recvData.ReadByteSeq(itemGuids[i][6]); + recvData.ReadByteSeq(itemGuids[i][1]); + recvData.ReadByteSeq(itemGuids[i][0]); + recvData.ReadByteSeq(itemGuids[i][2]); + recvData.ReadByteSeq(itemGuids[i][4]); + recvData.ReadByteSeq(itemGuids[i][5]); + recvData.ReadByteSeq(itemGuids[i][3]); + recvData.ReadByteSeq(itemGuids[i][7]); + } + + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(npcGuid[6]); + + for (uint32 i = 0; i < countWithdraw; ++i) + { + recvData.ReadByteSeq(itemIds[i][3]); + recvData.ReadByteSeq(itemIds[i][1]); + recvData.ReadByteSeq(itemIds[i][0]); + recvData.ReadByteSeq(itemIds[i][6]); + recvData.ReadByteSeq(itemIds[i][2]); + recvData.ReadByteSeq(itemIds[i][7]); + recvData.ReadByteSeq(itemIds[i][5]); + recvData.ReadByteSeq(itemIds[i][4]); + } + + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[0]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (!player->IsVoidStorageUnlocked()) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName()); + return; + } + + if (itemGuids.size() > player->GetNumOfVoidStorageFreeSlots()) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_FULL); + return; + } + + uint32 freeBagSlots = 0; + if (itemIds.size() != 0) + { + // make this a Player function + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + if (Bag* bag = player->GetBagByPos(i)) + freeBagSlots += bag->GetFreeSlots(); + for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) + if (!player->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + ++freeBagSlots; + } + + if (itemIds.size() > freeBagSlots) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INVENTORY_FULL); + return; + } + + if (!player->HasEnoughMoney(uint64(itemGuids.size() * VOID_STORAGE_STORE_ITEM))) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_NOT_ENOUGH_MONEY); + return; + } + + std::pair<VoidStorageItem, uint8> depositItems[VOID_STORAGE_MAX_DEPOSIT]; + uint8 depositCount = 0; + for (std::vector<ObjectGuid>::iterator itr = itemGuids.begin(); itr != itemGuids.end(); ++itr) + { + Item* item = player->GetItemByGuid(*itr); + if (!item) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) wants to deposit an invalid item (item guid: %u).", player->GetGUIDLow(), player->GetName(), *itr); + continue; + } + + VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetUInt64Value(ITEM_FIELD_CREATOR)); + + uint8 slot = player->AddVoidStorageItem(itemVS); + + depositItems[depositCount++] = std::make_pair(itemVS, slot); + + player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); + } + + int64 cost = depositCount * VOID_STORAGE_STORE_ITEM; + + player->ModifyMoney(-cost); + + VoidStorageItem withdrawItems[VOID_STORAGE_MAX_WITHDRAW]; + uint8 withdrawCount = 0; + for (std::vector<ObjectGuid>::iterator itr = itemIds.begin(); itr != itemIds.end(); ++itr) + { + uint8 slot; + VoidStorageItem* itemVS = player->GetVoidStorageItem(*itr, slot); + if (!itemVS) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) tried to withdraw an invalid item (id: %u)", player->GetGUIDLow(), player->GetName(), *itr); + continue; + } + + ItemPosCountVec dest; + InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemVS->ItemEntry, 1); + if (msg != EQUIP_ERR_OK) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INVENTORY_FULL); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidStorageTransfer - Player (GUID: %u, name: %s) couldn't withdraw item id %u because inventory was full.", player->GetGUIDLow(), player->GetName(), *itr); + return; + } + + Item* item = player->StoreNewItem(dest, itemVS->ItemEntry, true); + item->SetUInt64Value(ITEM_FIELD_CREATOR, uint64(itemVS->CreatorGuid)); + player->SendNewItem(item, 1, true, false, false); + + withdrawItems[withdrawCount++] = *itemVS; + + player->DeleteVoidStorageItem(slot); + } + + WorldPacket data(SMSG_VOID_STORAGE_TRANSFER_CHANGES, ((5 + 5 + (7 + 7) * depositCount + + 7 * withdrawCount) / 8) + 7 * withdrawCount + (7 + 7 + 4 * 4) * depositCount); + + data.WriteBits(depositCount, 5); + data.WriteBits(withdrawCount, 5); + + for (uint8 i = 0; i < depositCount; ++i) + { + ObjectGuid itemId = depositItems[i].first.ItemId; + ObjectGuid creatorGuid = depositItems[i].first.CreatorGuid; + data.WriteBit(creatorGuid[7]); + data.WriteBit(itemId[7]); + data.WriteBit(itemId[4]); + data.WriteBit(creatorGuid[6]); + data.WriteBit(creatorGuid[5]); + data.WriteBit(itemId[3]); + data.WriteBit(itemId[5]); + data.WriteBit(creatorGuid[4]); + data.WriteBit(creatorGuid[2]); + data.WriteBit(creatorGuid[0]); + data.WriteBit(creatorGuid[3]); + data.WriteBit(creatorGuid[1]); + data.WriteBit(itemId[2]); + data.WriteBit(itemId[0]); + data.WriteBit(itemId[1]); + data.WriteBit(itemId[6]); + } + + for (uint8 i = 0; i < withdrawCount; ++i) + { + ObjectGuid itemId = withdrawItems[i].ItemId; + data.WriteBit(itemId[1]); + data.WriteBit(itemId[7]); + data.WriteBit(itemId[3]); + data.WriteBit(itemId[5]); + data.WriteBit(itemId[6]); + data.WriteBit(itemId[2]); + data.WriteBit(itemId[4]); + data.WriteBit(itemId[0]); + } + + data.FlushBits(); + + for (uint8 i = 0; i < withdrawCount; ++i) + { + ObjectGuid itemId = withdrawItems[i].ItemId; + data.WriteByteSeq(itemId[3]); + data.WriteByteSeq(itemId[1]); + data.WriteByteSeq(itemId[0]); + data.WriteByteSeq(itemId[2]); + data.WriteByteSeq(itemId[7]); + data.WriteByteSeq(itemId[5]); + data.WriteByteSeq(itemId[6]); + data.WriteByteSeq(itemId[4]); + } + + for (uint8 i = 0; i < depositCount; ++i) + { + ObjectGuid itemId = depositItems[i].first.ItemId; + ObjectGuid creatorGuid = depositItems[i].first.CreatorGuid; + + data << int32(0); // unk + + data.WriteByteSeq(itemId[6]); + data.WriteByteSeq(itemId[4]); + data.WriteByteSeq(creatorGuid[4]); + data.WriteByteSeq(itemId[2]); + data.WriteByteSeq(creatorGuid[1]); + data.WriteByteSeq(creatorGuid[3]); + data.WriteByteSeq(itemId[3]); + data.WriteByteSeq(creatorGuid[0]); + data.WriteByteSeq(itemId[0]); + data.WriteByteSeq(creatorGuid[6]); + data.WriteByteSeq(itemId[5]); + data.WriteByteSeq(creatorGuid[5]); + data.WriteByteSeq(creatorGuid[7]); + + data << uint32(depositItems[i].first.ItemEntry); + + data.WriteByteSeq(itemId[1]); + + data << uint32(depositItems[i].second); // slot + + data.WriteByteSeq(creatorGuid[2]); + data.WriteByteSeq(itemId[7]); + + data << int32(0); // unk + } + + SendPacket(&data); + + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_NO_ERROR); +} + +void WorldSession::HandleVoidSwapItem(WorldPacket& recvData) +{ + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_VOID_SWAP_ITEM"); + + Player* player = GetPlayer(); + uint32 newSlot; + ObjectGuid npcGuid; + ObjectGuid itemId; + + recvData >> uint32(newSlot); + + npcGuid[2] = recvData.ReadBit(); + npcGuid[4] = recvData.ReadBit(); + npcGuid[0] = recvData.ReadBit(); + itemId[2] = recvData.ReadBit(); + itemId[6] = recvData.ReadBit(); + itemId[5] = recvData.ReadBit(); + npcGuid[1] = recvData.ReadBit(); + npcGuid[7] = recvData.ReadBit(); + itemId[3] = recvData.ReadBit(); + itemId[7] = recvData.ReadBit(); + itemId[0] = recvData.ReadBit(); + npcGuid[6] = recvData.ReadBit(); + npcGuid[5] = recvData.ReadBit(); + npcGuid[3] = recvData.ReadBit(); + itemId[1] = recvData.ReadBit(); + itemId[4] = recvData.ReadBit(); + + recvData.ReadByteSeq(npcGuid[1]); + recvData.ReadByteSeq(itemId[3]); + recvData.ReadByteSeq(itemId[2]); + recvData.ReadByteSeq(itemId[4]); + recvData.ReadByteSeq(npcGuid[3]); + recvData.ReadByteSeq(npcGuid[0]); + recvData.ReadByteSeq(itemId[6]); + recvData.ReadByteSeq(itemId[1]); + recvData.ReadByteSeq(npcGuid[5]); + recvData.ReadByteSeq(itemId[5]); + recvData.ReadByteSeq(npcGuid[6]); + recvData.ReadByteSeq(itemId[0]); + recvData.ReadByteSeq(npcGuid[2]); + recvData.ReadByteSeq(npcGuid[7]); + recvData.ReadByteSeq(npcGuid[4]); + recvData.ReadByteSeq(itemId[7]); + + Creature* unit = player->GetNPCIfCanInteractWith(npcGuid, UNIT_NPC_FLAG_VAULTKEEPER); + if (!unit) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidSwapItem - Unit (GUID: %u) not found or player can't interact with it.", GUID_LOPART(npcGuid)); + return; + } + + if (!player->IsVoidStorageUnlocked()) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidSwapItem - Player (GUID: %u, name: %s) queried void storage without unlocking it.", player->GetGUIDLow(), player->GetName()); + return; + } + + uint8 oldSlot; + if (!player->GetVoidStorageItem(itemId, oldSlot)) + { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleVoidSwapItem - Player (GUID: %u, name: %s) requested swapping an invalid item (slot: %u, itemid: %u).", player->GetGUIDLow(), player->GetName(), newSlot, itemId); + return; + } + + bool usedSrcSlot = player->GetVoidStorageItem(oldSlot) != NULL; // should be always true + bool usedDestSlot = player->GetVoidStorageItem(newSlot) != NULL; + ObjectGuid itemIdDest; + if (usedDestSlot) + itemIdDest = player->GetVoidStorageItem(newSlot)->ItemId; + + if (!player->SwapVoidStorageItem(oldSlot, newSlot)) + { + SendVoidStorageTransferResult(VOID_TRANSFER_ERROR_INTERNAL_ERROR_1); + return; + } + + WorldPacket data(SMSG_VOID_ITEM_SWAP_RESPONSE, 1 + (usedSrcSlot + usedDestSlot) * (1 + 7 + 4)); + + data.WriteBit(!usedDestSlot); + data.WriteBit(!usedSrcSlot); + + if (usedSrcSlot) + { + data.WriteBit(itemId[5]); + data.WriteBit(itemId[2]); + data.WriteBit(itemId[1]); + data.WriteBit(itemId[4]); + data.WriteBit(itemId[0]); + data.WriteBit(itemId[6]); + data.WriteBit(itemId[7]); + data.WriteBit(itemId[3]); + } + + data.WriteBit(!usedDestSlot); // unk + + if (usedDestSlot) + { + data.WriteBit(itemIdDest[7]); + data.WriteBit(itemIdDest[3]); + data.WriteBit(itemIdDest[4]); + data.WriteBit(itemIdDest[0]); + data.WriteBit(itemIdDest[5]); + data.WriteBit(itemIdDest[1]); + data.WriteBit(itemIdDest[2]); + data.WriteBit(itemIdDest[6]); + } + + data.WriteBit(!usedSrcSlot); // unk + + data.FlushBits(); + + if (usedDestSlot) + { + data.WriteByteSeq(itemIdDest[4]); + data.WriteByteSeq(itemIdDest[6]); + data.WriteByteSeq(itemIdDest[5]); + data.WriteByteSeq(itemIdDest[2]); + data.WriteByteSeq(itemIdDest[3]); + data.WriteByteSeq(itemIdDest[1]); + data.WriteByteSeq(itemIdDest[7]); + data.WriteByteSeq(itemIdDest[0]); + } + + if (usedSrcSlot) + { + data.WriteByteSeq(itemId[6]); + data.WriteByteSeq(itemId[3]); + data.WriteByteSeq(itemId[5]); + data.WriteByteSeq(itemId[0]); + data.WriteByteSeq(itemId[1]); + data.WriteByteSeq(itemId[2]); + data.WriteByteSeq(itemId[4]); + data.WriteByteSeq(itemId[7]); + } + + if (usedSrcSlot) + data << uint32(newSlot); + + if (usedDestSlot) + data << uint32(oldSlot); + + SendPacket(&data); +} diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 0b3dc884a1a..e17bbc0729f 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3667,4 +3667,24 @@ enum CalendarError // Calendar - end +#define VOID_STORAGE_UNLOCK 100*GOLD +#define VOID_STORAGE_STORE_ITEM 25*GOLD +#define VOID_STORAGE_MAX_DEPOSIT 9 +#define VOID_STORAGE_MAX_WITHDRAW 9 +#define VOID_STORAGE_MAX_SLOT 80 + +enum VoidTransferError +{ + VOID_TRANSFER_ERROR_NO_ERROR = 0, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_1 = 1, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_2 = 2, + VOID_TRANSFER_ERROR_FULL = 3, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_3 = 4, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_4 = 5, + VOID_TRANSFER_ERROR_NOT_ENOUGH_MONEY = 6, + VOID_TRANSFER_ERROR_INVENTORY_FULL = 7, + VOID_TRANSFER_ERROR_INTERNAL_ERROR_5 = 8, + VOID_TRANSFER_ERROR_TRANSFER_UNKNOWN = 9, +}; + #endif diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 301ebb12221..9fe345b9c5f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -82,12 +82,12 @@ void InitOpcodes() //DEFINE_OPCODE_HANDLER(CMSG_AUTH_SRP6_RECODE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_AUTOBANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoBankItemOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_GROUND_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - //DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_AUTOEQUIP_ITEM_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemSlotOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_BAG_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBagItemOpcode ); - //DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_BANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_BANK_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_GROUND_ITEM, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - //DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_BANKER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBankerActivateOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_JOIN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_BATTLEFIELD_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlefieldListOpcode ); @@ -631,7 +631,7 @@ void InitOpcodes() //DEFINE_OPCODE_HANDLER(CMSG_STORE_LOOT_IN_SLOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_SUMMON_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_SUSPEND_COMMS_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - //DEFINE_OPCODE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapInvItemOpcode ); + DEFINE_OPCODE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapInvItemOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapItem ); //DEFINE_OPCODE_HANDLER(CMSG_SYNC_DANCE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_TARGET_CAST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -655,7 +655,7 @@ void InitOpcodes() //DEFINE_OPCODE_HANDLER(CMSG_TRIGGER_CINEMATIC_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTurnInPetitionOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_CLEAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialClear ); - //DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_FLAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag ); + DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_FLAG, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag ); //DEFINE_OPCODE_HANDLER(CMSG_TUTORIAL_RESET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialReset ); DEFINE_OPCODE_HANDLER(CMSG_UNACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_UNCLAIM_LICENSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -676,6 +676,10 @@ void InitOpcodes() DEFINE_OPCODE_HANDLER(CMSG_VIOLENCE_LEVEL, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleViolenceLevel ); DEFINE_OPCODE_HANDLER(CMSG_VOICE_SESSION_ENABLE, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleVoiceSessionEnableOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_VOICE_SET_TALKER_MUTED_REQUEST, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_STORAGE_UNLOCK, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidStorageUnlock ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_STORAGE_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidStorageQuery ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_STORAGE_TRANSFER, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidStorageTransfer ); + DEFINE_OPCODE_HANDLER(CMSG_VOID_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleVoidSwapItem ); //DEFINE_OPCODE_HANDLER(CMSG_WARDEN_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleWardenDataOpcode ); //DEFINE_OPCODE_HANDLER(CMSG_WEATHER_SPEED_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); //DEFINE_OPCODE_HANDLER(CMSG_WHO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleWhoOpcode ); @@ -1042,7 +1046,7 @@ void InitOpcodes() DEFINE_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_ITEM_NAME_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - //DEFINE_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_ITEM_REFUND_INFO_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_ITEM_REFUND_RESULT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_ITEM_TEXT_QUERY_RESPONSE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); @@ -1380,6 +1384,11 @@ void InitOpcodes() //DEFINE_OPCODE_HANDLER(SMSG_VOICE_SESSION_LEAVE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_VOICE_SESSION_ROSTER_UPDATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_VOICE_SET_TALKER_MUTED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_ITEM_SWAP_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_STORAGE_CONTENTS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_STORAGE_TRANSFER_CHANGES, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_TRANSFER_RESULT, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_VOID_STORAGE_FAILED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_WARDEN_DATA, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_WEATHER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); //DEFINE_OPCODE_HANDLER(SMSG_WHO, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index c1fb3f940be..d286e33fcbb 100755 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -440,7 +440,6 @@ enum Opcodes CMSG_QUERY_INSPECT_ACHIEVEMENTS = 0x4D27, CMSG_QUERY_QUESTS_COMPLETED = 0x2317, CMSG_QUERY_TIME = 0x0A36, - CMSG_QUERY_VOID_STORAGE = 0x790A, CMSG_QUESTGIVER_ACCEPT_QUEST = 0x6B37, CMSG_QUESTGIVER_CANCEL = 0x0000, CMSG_QUESTGIVER_CHOOSE_REWARD = 0x2125, @@ -552,7 +551,6 @@ enum Opcodes CMSG_SUSPEND_TOKEN = 0x046D, CMSG_SWAP_INV_ITEM = 0x2614, CMSG_SWAP_ITEM = 0x6326, - CMSG_SWAP_VOID_ITEM = 0x3204, CMSG_SYNC_DANCE = 0x0036, CMSG_TAXICLEARALLNODES = 0x0000, CMSG_TAXIENABLEALLNODES = 0x0000, @@ -577,7 +575,6 @@ enum Opcodes CMSG_UNACCEPT_TRADE = 0x391A, CMSG_UNLEARN_SKILL = 0x6106, CMSG_UNLEARN_SPECIALIZATION = 0x3210, - CMSG_UNLOCK_VOID_STORAGE = 0x7B14, CMSG_UNREGISTER_ALL_ADDON_PREFIXES = 0x3D54, CMSG_UPDATE_ACCOUNT_DATA = 0x4736, CMSG_UPDATE_MISSILE_TRAJECTORY = 0x781E, @@ -586,7 +583,10 @@ enum Opcodes CMSG_USE_ITEM = 0x2C06, CMSG_VIOLENCE_LEVEL = 0x7816, CMSG_VOICE_SESSION_ENABLE = 0x2314, + CMSG_VOID_STORAGE_QUERY = 0x790A, CMSG_VOID_STORAGE_TRANSFER = 0x380E, + CMSG_VOID_STORAGE_UNLOCK = 0x7B14, + CMSG_VOID_SWAP_ITEM = 0x3204, CMSG_WARDEN_DATA = 0x25A2, CMSG_WARGAME_ACCEPT = 0x2410, CMSG_WARGAME_START = 0x05A0, diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 80c532e7430..c215063fefa 100755 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -911,6 +911,13 @@ class WorldSession void SendCalendarRaidLockoutUpdated(InstanceSave const* save); void SendCalendarCommandResult(CalendarError err, char const* param = NULL); + // Void Storage + void HandleVoidStorageUnlock(WorldPacket& recvData); + void HandleVoidStorageQuery(WorldPacket& recvData); + void HandleVoidStorageTransfer(WorldPacket& recvData); + void HandleVoidSwapItem(WorldPacket& recvData); + void SendVoidStorageTransferResult(VoidTransferError result); + void HandleSpellClick(WorldPacket& recv_data); void HandleMirrorImageDataRequest(WorldPacket& recv_data); void HandleAlterAppearance(WorldPacket& recv_data); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 75fbdbf78f8..d1544d43232 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -555,4 +555,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, spell, spec) VALUES (?, ?, ?)", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, "DELETE FROM character_action WHERE spec<>? AND guid = ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND slot = ?", CONNECTION_SYNCH); + + PREPARE_STATEMENT(CHAR_SEL_VOID_STORAGE, "SELECT itemid, itemEntry, slot, creatorGuid FROM void_storage WHERE playerGuid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_REP_VOID_STORAGE_ITEM, "REPLACE INTO void_Storage (itemId, playerGuid, itemEntry, slot, creatorGuid) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_DEL_VOID_STORAGE_ITEM_BY_SLOT, "DELETE FROM void_Storage WHERE slot = ? AND playerGuid = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index c0ab078dfe3..5dac60d6ba8 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -519,6 +519,10 @@ enum CharacterDatabaseStatements CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT, + CHAR_SEL_VOID_STORAGE, + CHAR_REP_VOID_STORAGE_ITEM, + CHAR_DEL_VOID_STORAGE_ITEM_BY_SLOT, + MAX_CHARACTERDATABASE_STATEMENTS, }; |
