aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2017-08-20 14:11:51 +0200
committerShauren <shauren.trinity@gmail.com>2017-08-20 14:12:25 +0200
commitfb1fdf27b951fafbcb68c97675f75ef98aa5e3b7 (patch)
tree231abb9641515e0e75abdcf09b5f0ef7dfbc962b
parent6a296c7c91fe00144c858b8a611537da05d7e8ac (diff)
Core/Creatures: Fixed trainers that don't use gossip but open trainer list directly from CMSG_TRAINER_LIST
-rw-r--r--sql/updates/world/master/2017_08_20_00_world.sql9
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp42
-rw-r--r--src/server/game/Globals/ObjectMgr.h3
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp25
-rw-r--r--src/server/game/Server/WorldSession.h2
-rw-r--r--src/server/game/World/World.cpp3
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp2
8 files changed, 75 insertions, 13 deletions
diff --git a/sql/updates/world/master/2017_08_20_00_world.sql b/sql/updates/world/master/2017_08_20_00_world.sql
new file mode 100644
index 00000000000..d77b9d46ae3
--- /dev/null
+++ b/sql/updates/world/master/2017_08_20_00_world.sql
@@ -0,0 +1,9 @@
+--
+-- Table structure for table `creature_default_trainer`
+--
+DROP TABLE IF EXISTS `creature_default_trainer`;
+CREATE TABLE `creature_default_trainer` (
+ `CreatureId` int(11) UNSIGNED NOT NULL,
+ `TrainerId` int(11) UNSIGNED NOT NULL DEFAULT '0',
+ PRIMARY KEY (`CreatureId`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 3e4a4768cfe..9f5a82f96ea 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14324,7 +14324,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men
GetSession()->SendStablePet(guid);
break;
case GOSSIP_OPTION_TRAINER:
- GetSession()->SendTrainerList(guid, menuItemData->TrainerId);
+ GetSession()->SendTrainerList(source->ToCreature(), menuItemData->TrainerId);
break;
case GOSSIP_OPTION_LEARNDUALSPEC:
break;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 1db80ed6001..2d489977e79 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8633,6 +8633,39 @@ void ObjectMgr::LoadTrainers()
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Trainers in %u ms", _trainers.size(), GetMSTimeDiffToNow(oldMSTime));
}
+void ObjectMgr::LoadCreatureDefaultTrainers()
+{
+ uint32 oldMSTime = getMSTime();
+
+ _creatureDefaultTrainers.clear();
+
+ if (QueryResult result = WorldDatabase.Query("SELECT CreatureId, TrainerId FROM creature_default_trainer"))
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 creatureId = fields[0].GetUInt32();
+ uint32 trainerId = fields[1].GetUInt32();
+
+ if (!GetCreatureTemplate(creatureId))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing creature template (CreatureId: %u), ignoring", creatureId);
+ continue;
+ }
+
+ if (!GetTrainer(trainerId))
+ {
+ TC_LOG_ERROR("sql.sql", "Table `trainer_spell` references non-existing trainer (TrainerId: %u) for CreatureId %u, ignoring", trainerId, creatureId);
+ continue;
+ }
+
+ _creatureDefaultTrainers[creatureId] = trainerId;
+ } while (result->NextRow());
+ }
+
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " default trainers in %u ms", _creatureDefaultTrainers.size(), GetMSTimeDiffToNow(oldMSTime));
+}
+
int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, uint8 referenceType, std::set<uint32> *skip_vendors)
{
// find all items from the reference vendor
@@ -8868,6 +8901,15 @@ Trainer::Trainer const* ObjectMgr::GetTrainer(uint32 trainerId) const
return Trinity::Containers::MapGetValuePtr(_trainers, trainerId);
}
+uint32 ObjectMgr::GetCreatureDefaultTrainer(uint32 creatureId) const
+{
+ auto itr = _creatureDefaultTrainers.find(creatureId);
+ if (itr != _creatureDefaultTrainers.end())
+ return itr->second;
+
+ return 0;
+}
+
void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist /*= true*/)
{
VendorItemData& vList = _cacheVendorItemStore[entry];
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index aad57743e82..ff394c9ed3d 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1166,6 +1166,7 @@ class TC_GAME_API ObjectMgr
void LoadVendors();
void LoadTrainers();
+ void LoadCreatureDefaultTrainers();
void LoadTerrainPhaseInfo();
void LoadTerrainSwapDefaults();
@@ -1379,6 +1380,7 @@ class TC_GAME_API ObjectMgr
bool DeleteGameTele(std::string const& name);
Trainer::Trainer const* GetTrainer(uint32 trainerId) const;
+ uint32 GetCreatureDefaultTrainer(uint32 creatureId) const;
VendorItemData const* GetNpcVendorItemList(uint32 entry) const
{
@@ -1659,6 +1661,7 @@ class TC_GAME_API ObjectMgr
CacheVendorItemContainer _cacheVendorItemStore;
std::unordered_map<uint32, Trainer::Trainer> _trainers;
+ std::unordered_map<uint32, uint32> _creatureDefaultTrainers;
std::set<uint32> _difficultyEntries[MAX_CREATURE_DIFFICULTIES]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate
std::set<uint32> _hasDifficultyEntries[MAX_CREATURE_DIFFICULTIES]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 6d16a63d81a..51c6e29776f 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -90,18 +90,21 @@ void WorldSession::SendShowMailBox(ObjectGuid guid)
void WorldSession::HandleTrainerListOpcode(WorldPackets::NPC::Hello& packet)
{
- TC_LOG_INFO("network", "%s sent legacy gossipless trainer hello for unit %s, no trainer list available", GetPlayerInfo().c_str(), packet.Unit.ToString().c_str());
-}
-
-void WorldSession::SendTrainerList(ObjectGuid guid, uint32 trainerId)
-{
- Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
- if (!unit)
+ Creature* npc = GetPlayer()->GetNPCIfCanInteractWith(packet.Unit, UNIT_NPC_FLAG_TRAINER);
+ if (!npc)
{
- TC_LOG_DEBUG("network", "WORLD: SendTrainerList - %s not found or you can not interact with him.", guid.ToString().c_str());
+ TC_LOG_DEBUG("network", "WorldSession::SendTrainerList - %s not found or you can not interact with him.", packet.Unit.ToString().c_str());
return;
}
+ if (uint32 trainerId = sObjectMgr->GetCreatureDefaultTrainer(npc->GetEntry()))
+ SendTrainerList(npc, trainerId);
+ else
+ TC_LOG_DEBUG("network", "WorldSession::SendTrainerList - Creature id %u has no trainer data.", npc->GetEntry());
+}
+
+void WorldSession::SendTrainerList(Creature* npc, uint32 trainerId)
+{
// remove fake death
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
@@ -109,14 +112,14 @@ void WorldSession::SendTrainerList(ObjectGuid guid, uint32 trainerId)
Trainer::Trainer const* trainer = sObjectMgr->GetTrainer(trainerId);
if (!trainer)
{
- TC_LOG_DEBUG("network", "WORLD: SendTrainerList - trainer spells not found for trainer %s id %d", guid.ToString().c_str(), trainerId);
+ TC_LOG_DEBUG("network", "WorldSession::SendTrainerList - trainer spells not found for trainer %s id %d", npc->GetGUID().ToString().c_str(), trainerId);
return;
}
_player->PlayerTalkClass->GetInteractionData().Reset();
- _player->PlayerTalkClass->GetInteractionData().SourceGuid = guid;
+ _player->PlayerTalkClass->GetInteractionData().SourceGuid = npc->GetGUID();
_player->PlayerTalkClass->GetInteractionData().TrainerId = trainerId;
- trainer->SendSpells(unit, _player, GetSessionDbLocaleIndex());
+ trainer->SendSpells(npc, _player, GetSessionDbLocaleIndex());
}
void WorldSession::HandleTrainerBuySpellOpcode(WorldPackets::NPC::TrainerBuySpell& packet)
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 2addad0b5c2..d2e39197b10 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -972,7 +972,7 @@ class TC_GAME_API WorldSession
void SendNameQueryOpcode(ObjectGuid guid);
- void SendTrainerList(ObjectGuid guid, uint32 trainerId);
+ void SendTrainerList(Creature* npc, uint32 trainerId);
void SendListInventory(ObjectGuid guid);
void SendShowBank(ObjectGuid guid);
bool CanOpenMailBox(ObjectGuid guid);
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4234d3720e8..1b15c75b08f 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1939,6 +1939,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Trainers...");
sObjectMgr->LoadTrainers(); // must be after load CreatureTemplate
+ TC_LOG_INFO("server.loading", "Loading Creature default trainers...");
+ sObjectMgr->LoadCreatureDefaultTrainers();
+
TC_LOG_INFO("server.loading", "Loading Gossip menu...");
sObjectMgr->LoadGossipMenu();
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index b657e9e56fe..d1c9396af5a 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -693,9 +693,11 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading `trainer` Table!");
sObjectMgr->LoadTrainers();
+ sObjectMgr->LoadCreatureDefaultTrainers();
handler->SendGlobalGMSysMessage("DB table `trainer` reloaded.");
handler->SendGlobalGMSysMessage("DB table `trainer_locale` reloaded.");
handler->SendGlobalGMSysMessage("DB table `trainer_spell` reloaded.");
+ handler->SendGlobalGMSysMessage("DB table `creature_default_trainer` reloaded.");
return true;
}