From e51220bf87b7cbc75d4de5da79974e820caa4720 Mon Sep 17 00:00:00 2001 From: Aokromes Date: Wed, 10 Aug 2016 21:04:30 +0200 Subject: [PATCH] Core/Handlers: actually check allowed trainer classes and races to avoid spoofing --- src/server/game/Entities/Player/Player.cpp | 5 ++++- src/server/game/Handlers/NPCHandler.cpp | 24 ++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a63f98584f..d189e415ab 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14097,8 +14097,11 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool break; case GOSSIP_OPTION_TRAINER: if (getClass() != creature->GetCreatureTemplate()->trainer_class && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS) + { TC_LOG_ERROR("sql.sql", "GOSSIP_OPTION_TRAINER:: Player %s (GUID: %u) requested wrong gossip menu: %u with wrong class: %u at Creature: %s (Entry: %u, Trainer Class: %u)", - GetName().c_str(), GetGUID().GetCounter(), menu->GetGossipMenu().GetMenuId(), getClass(), creature->GetName().c_str(), creature->GetEntry(), creature->GetCreatureTemplate()->trainer_class); + GetName().c_str(), GetGUID().GetCounter(), menu->GetGossipMenu().GetMenuId(), getClass(), creature->GetName().c_str(), creature->GetEntry(), creature->GetCreatureTemplate()->trainer_class); + canTalk = false; + } // no break; case GOSSIP_OPTION_GOSSIP: case GOSSIP_OPTION_SPIRITGUIDE: diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 7e45de8a6d..feaeb5a7d0 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -128,8 +128,8 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) { TC_LOG_DEBUG("network", "WORLD: SendTrainerList"); - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); - if (!unit) + Creature* trainer = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + if (!trainer) { TC_LOG_DEBUG("network", "WORLD: SendTrainerList - %s not found or you can not interact with him.", guid.ToString().c_str()); return; @@ -251,8 +251,20 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + // check race for mount trainers + if (trainer->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_MOUNTS) + { + if (uint32 trainerRace = trainer->GetCreatureTemplate()->trainer_race) + if (_player->getRace() != trainerRace) + return; + } + + // check class for class trainers + if (_player->getClass() != trainer->GetCreatureTemplate()->trainer_class && trainer->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS) + return; + // check present spell in trainer spell list - TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); + TrainerSpellData const* trainer_spells = trainer->GetTrainerSpells(); if (!trainer_spells) { SendTrainerBuyFailed(guid, spellId, 0); @@ -275,7 +287,7 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) } // apply reputation discount - uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(unit))); + uint32 nSpellCost = uint32(floor(trainer_spell->spellCost * _player->GetReputationPriceDiscount(trainer))); // check money requirement if (!_player->HasEnoughMoney(uint64(nSpellCost))) @@ -286,8 +298,8 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) _player->ModifyMoney(-int64(nSpellCost)); - unit->SendPlaySpellVisualKit(179, 0); // 53 SpellCastDirected - _player->SendPlaySpellVisualKit(362, 1); // 113 EmoteSalute + trainer->SendPlaySpellVisual(179); // 53 SpellCastDirected + trainer->SendPlaySpellImpact(_player->GetGUID(), 362); // 113 EmoteSalute // learn explicitly or cast explicitly if (trainer_spell->IsCastable())