Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Entities/Player/Player.h
This commit is contained in:
郑佩茹
2023-03-16 10:00:13 -06:00
325 changed files with 12322 additions and 7378 deletions
@@ -577,6 +577,7 @@ void BossAI::_Reset()
events.Reset();
scheduler.CancelAll();
summons.DespawnAll();
_healthCheckEvents.clear();
if (instance)
instance->SetBossState(_bossId, NOT_STARTED);
}
@@ -586,6 +587,7 @@ void BossAI::_JustDied()
events.Reset();
scheduler.CancelAll();
summons.DespawnAll();
_healthCheckEvents.clear();
if (instance)
{
instance->SetBossState(_bossId, DONE);
@@ -667,6 +669,39 @@ void BossAI::UpdateAI(uint32 diff)
DoMeleeAttackIfReady();
}
void BossAI::DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/)
{
if (!_healthCheckEvents.empty())
{
_healthCheckEvents.remove_if([&](HealthCheckEventData data) -> bool
{
return _ProccessHealthCheckEvent(data._healthPct, damage, data._exec);
});
}
}
/**
* @brief Executes a function once the creature reaches the defined health point percent.
*
* @param healthPct The health percent at which the code will be executed.
* @param exec The fuction to be executed.
*/
void BossAI::ScheduleHealthCheckEvent(uint32 healthPct, std::function<void()> exec)
{
_healthCheckEvents.push_back(HealthCheckEventData(healthPct, exec));
};
bool BossAI::_ProccessHealthCheckEvent(uint8 healthPct, uint32 damage, std::function<void()> exec) const
{
if (me->HealthBelowPctDamaged(healthPct, damage))
{
exec();
return true;
}
return false;
}
// WorldBossAI - for non-instanced bosses
WorldBossAI::WorldBossAI(Creature* creature) :
@@ -139,6 +139,20 @@ public:
}
}
void DoForAllSummons(std::function<void(WorldObject*)> exec)
{
// We need to use a copy of SummonList here, otherwise original SummonList would be modified
StorageType listCopy = storage_;
for (auto const& guid : listCopy)
{
if (WorldObject* summon = ObjectAccessor::GetWorldObject(*me, guid))
{
exec(summon);
}
}
}
void DoZoneInCombat(uint32 entry = 0);
void RemoveNotExisting();
bool HasEntry(uint32 entry) const;
@@ -430,6 +444,14 @@ private:
bool _isHeroic;
};
struct HealthCheckEventData
{
HealthCheckEventData(uint8 healthPct, std::function<void()> exec) : _healthPct(healthPct), _exec(exec) { };
uint8 _healthPct;
std::function<void()> _exec;
};
class BossAI : public ScriptedAI
{
public:
@@ -440,12 +462,15 @@ public:
bool CanRespawn() override;
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override;
void JustSummoned(Creature* summon) override;
void SummonedCreatureDespawn(Creature* summon) override;
void SummonedCreatureDespawnAll() override;
void UpdateAI(uint32 diff) override;
void ScheduleHealthCheckEvent(uint32 healthPct, std::function<void()> exec);
// Hook used to execute events scheduled into EventMap without the need
// to override UpdateAI
// note: You must re-schedule the event within this method if the event
@@ -464,6 +489,7 @@ protected:
void _JustEngagedWith();
void _JustDied();
void _JustReachedHome() { me->setActive(false); }
[[nodiscard]] bool _ProccessHealthCheckEvent(uint8 healthPct, uint32 damage, std::function<void()> exec) const;
void TeleportCheaters();
@@ -473,6 +499,7 @@ protected:
private:
uint32 const _bossId;
std::list<HealthCheckEventData> _healthCheckEvents;
};
class WorldBossAI : public ScriptedAI
@@ -129,12 +129,12 @@ void AutobroadcastMgr::SendAutobroadcasts()
LOG_DEBUG("autobroadcast", "AutobroadcastMgr::SendAutobroadcasts: '{}'", msg);
}
void AutobroadcastMgr::SendWorldAnnouncement(std::string_view msg)
void AutobroadcastMgr::SendWorldAnnouncement(std::string msg)
{
sWorld->SendWorldTextOptional(LANG_AUTO_BROADCAST, ANNOUNCER_FLAG_DISABLE_AUTOBROADCAST, msg.data());
}
void AutobroadcastMgr::SendNotificationAnnouncement(std::string_view msg)
void AutobroadcastMgr::SendNotificationAnnouncement(std::string msg)
{
WorldPacket data(SMSG_NOTIFICATION, (msg.size() + 1));
data << msg.data();
@@ -37,8 +37,8 @@ public:
void SendAutobroadcasts();
private:
void SendWorldAnnouncement(std::string_view msg);
void SendNotificationAnnouncement(std::string_view msg);
void SendWorldAnnouncement(std::string msg);
void SendNotificationAnnouncement(std::string msg);
typedef std::map<uint8, std::string> AutobroadcastsMap;
typedef std::map<uint8, uint8> AutobroadcastsWeightMap;
+1 -1
View File
@@ -281,7 +281,7 @@ bool ArenaTeam::LoadMembersFromDB(QueryResult result)
bool ArenaTeam::SetName(std::string const& name)
{
if (TeamName == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
if (TeamName == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || sObjectMgr->IsProfanityName(name) || !ObjectMgr::IsValidCharterName(name))
return false;
TeamName = name;
@@ -895,8 +895,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId
{
if (!(*itr3)->IsInvitedToBGInstanceGUID
&& (((*itr3)->ArenaMatchmakerRating >= arenaMinRating && (*itr3)->ArenaMatchmakerRating <= arenaMaxRating) || (int32)(*itr3)->JoinTime < discardTime)
&& ((*itr_teams[0])->ArenaTeamId != (*itr3)->PreviousOpponentsTeamId || ((int32)(*itr3)->JoinTime < discardOpponentsTime))
&& (*itr_teams[0])->ArenaTeamId != (*itr3)->ArenaTeamId)
&& ((*(itr_teams[0]))->ArenaTeamId != (*itr3)->PreviousOpponentsTeamId || ((int32)(*itr3)->JoinTime < discardOpponentsTime))
&& (*(itr_teams[0]))->ArenaTeamId != (*itr3)->ArenaTeamId)
{
itr_teams[found++] = itr3;
break;
@@ -907,8 +907,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(uint32 diff, BattlegroundTypeId
//if we have 2 teams, then start new arena and invite players!
if (found == 2)
{
GroupQueueInfo* aTeam = *itr_teams[TEAM_ALLIANCE];
GroupQueueInfo* hTeam = *itr_teams[TEAM_HORDE];
GroupQueueInfo* aTeam = *(itr_teams[TEAM_ALLIANCE]);
GroupQueueInfo* hTeam = *(itr_teams[TEAM_HORDE]);
Battleground* arena = sBattlegroundMgr->CreateNewBattleground(bgTypeId, bracketEntry, arenaType, true);
if (!arena)
+1 -10
View File
@@ -459,17 +459,8 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
float runSpeed = cinfo->speed_run;
if (Pet* pet = ToPet())
{
if (pet->isControlled() && pet->GetOwnerGUID().IsPlayer())
{
runSpeed = 1.15f;
}
}
SetSpeed(MOVE_WALK, cinfo->speed_walk);
SetSpeed(MOVE_RUN, runSpeed);
SetSpeed(MOVE_RUN, cinfo->speed_run);
SetSpeed(MOVE_SWIM, cinfo->speed_swim);
SetSpeed(MOVE_FLIGHT, cinfo->speed_flight);
@@ -392,6 +392,12 @@ public:
void ModifyThreatPercentTemp(Unit* victim, int32 percent, Milliseconds duration);
/**
* @brief Helper to resume chasing current victim.
*
* */
void ResumeChasingVictim() { GetMotionMaster()->MoveChase(GetVictim()); };
std::string GetDebugInfo() const override;
protected:
@@ -1344,7 +1344,7 @@ bool GameObject::ActivateToQuest(Player* target) const
case GAMEOBJECT_TYPE_CHEST:
{
// scan GO chest with loot including quest items
if (LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->GetLootId(), target))
if (target->GetQuestStatus(GetGOInfo()->chest.questId) == QUEST_STATUS_INCOMPLETE || LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->GetLootId(), target))
{
//TODO: fix this hack
//look for battlegroundAV for some objects which are only activated after mine gots captured by own team
+5
View File
@@ -1048,6 +1048,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
else if (petType != SUMMON_PET)
LOG_ERROR("entities.pet", "Unknown type pet {} is summoned by player class {}", GetEntry(), owner->getClass());
}
if (petType == HUNTER_PET || petType == SUMMON_PET)
{
SetSpeed(MOVE_RUN, 1.15f);
}
}
uint32 creature_ID = (petType == HUNTER_PET) ? 1 : cinfo->Entry;
+28 -23
View File
@@ -9185,32 +9185,47 @@ Pet* Player::CreatePet(uint32 creatureEntry, uint32 spellID /*= 0*/)
return pet;
}
void Player::StopCastingCharm()
void Player::StopCastingCharm(Aura* except /*= nullptr*/)
{
Unit* charm = GetCharm();
if (!charm)
{
return;
}
if (charm->GetTypeId() == TYPEID_UNIT)
{
if (charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET))
{
((Puppet*)charm)->UnSummon();
}
else if (charm->IsVehicle())
{
ExitVehicle();
}
}
if (GetCharmGUID())
charm->RemoveCharmAuras();
{
charm->RemoveAurasByType(SPELL_AURA_MOD_CHARM, ObjectGuid::Empty, except);
charm->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, ObjectGuid::Empty, except);
charm->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, ObjectGuid::Empty, except);
charm->RemoveAurasByType(SPELL_AURA_AOE_CHARM, ObjectGuid::Empty, except);
}
if (GetCharmGUID())
{
LOG_FATAL("entities.player", "Player {} ({} is not able to uncharm unit ({})", GetName(), GetGUID().ToString(), GetCharmGUID().ToString());
if (charm->GetCharmerGUID())
{
LOG_FATAL("entities.player", "Charmed unit has charmer {}", charm->GetCharmerGUID().ToString());
ABORT();
}
else
{
SetCharm(charm, false);
}
}
}
@@ -10800,7 +10815,6 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
// cooldown information stored in item prototype
// This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
bool useSpellCooldown = spellInfo->HasAttribute(SPELL_ATTR7_CAN_BE_MULTI_CAST);
if (itemId)
{
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
@@ -10812,12 +10826,6 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
cat = proto->Spells[idx].SpellCategory;
rec = proto->Spells[idx].SpellCooldown;
catrec = proto->Spells[idx].SpellCategoryCooldown;
if (static_cast<int32>(cat) != catrec)
{
useSpellCooldown = true;
}
break;
}
}
@@ -10854,14 +10862,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
// Now we have cooldown data (if found any), time to apply mods
if (rec > 0)
{
int32 oldRec = rec;
ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
if (oldRec != rec)
{
useSpellCooldown = true;
}
}
if (catrec > 0 && !spellInfo->HasAttribute(SPELL_ATTR6_NO_CATEGORY_COOLDOWN_MODS))
{
@@ -10874,7 +10875,6 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
if (HasSpell(spellInfo->Id))
{
needsCooldownPacket = true;
useSpellCooldown = true;
rec += cooldownMod * IN_MILLISECONDS; // SPELL_AURA_MOD_COOLDOWN does not affect category cooldows, verified with shaman shocks
}
}
@@ -10894,11 +10894,11 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
// category spells
if (cat && catrec > 0)
{
_AddSpellCooldown(spellInfo->Id, cat, itemId, useSpellCooldown ? recTime : catrecTime, true, true);
_AddSpellCooldown(spellInfo->Id, 0, itemId, recTime, true, true);
if (needsCooldownPacket)
{
WorldPacket data;
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, useSpellCooldown ? recTime : catrecTime);
BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, recTime);
SendDirectMessage(&data);
}
@@ -13048,15 +13048,15 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
return false;
}
void Player::StopCastingBindSight()
void Player::StopCastingBindSight(Aura* except /*= nullptr*/)
{
if (WorldObject* target = GetViewpoint())
{
if (target->isType(TYPEMASK_UNIT))
{
((Unit*)target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID());
((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID());
((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID());
((Unit*)target)->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID(), except);
((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID(), except);
((Unit*)target)->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID(), except);
}
}
}
@@ -16237,3 +16237,8 @@ std::string Player::GetDebugInfo() const
sstr << Unit::GetDebugInfo();
return sstr.str();
}
void Player::SendSystemMessage(std::string_view msg, bool escapeCharacters)
{
ChatHandler(GetSession()).SendSysMessage(msg, escapeCharacters);
}
+4 -2
View File
@@ -2298,8 +2298,8 @@ public:
void SetSeer(WorldObject* target) { m_seer = target; }
void SetViewpoint(WorldObject* target, bool apply);
[[nodiscard]] WorldObject* GetViewpoint() const;
void StopCastingCharm();
void StopCastingBindSight();
void StopCastingCharm(Aura* except = nullptr);
void StopCastingBindSight(Aura* except = nullptr);
[[nodiscard]] uint32 GetSaveTimer() const { return m_nextSave; }
void SetSaveTimer(uint32 timer) { m_nextSave = timer; }
@@ -2575,6 +2575,8 @@ public:
[[nodiscard]] PlayerSetting GetPlayerSetting(std::string source, uint8 index);
void UpdatePlayerSetting(std::string source, uint8 index, uint32 value);
void SendSystemMessage(std::string_view msg, bool escapeCharacters = false);
void ResetSpeakTimers();
std::string GetDebugInfo() const override;
@@ -1314,6 +1314,7 @@ bool Player::SatisfyQuestSeasonal(Quest const* qInfo, bool /*msg*/) const
if (!qInfo->IsSeasonal() || m_seasonalquests.empty())
return true;
// cppcheck-suppress mismatchingContainers
Player::SeasonalEventQuestMap::iterator itr = ((Player*)this)->m_seasonalquests.find(qInfo->GetEventIdForQuest());
if (itr == m_seasonalquests.end() || itr->second.empty())
@@ -4990,7 +4990,7 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
// check name limitations
if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS ||
(AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && sObjectMgr->IsReservedName(m_name)))
(AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && (sObjectMgr->IsReservedName(m_name) || sObjectMgr->IsProfanityName(m_name))))
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
stmt->SetData(0, uint16(AT_LOGIN_RENAME));
+52 -29
View File
@@ -10717,11 +10717,6 @@ void Unit::SetMinion(Minion* minion, bool apply)
// PvP, FFAPvP
minion->SetByteValue(UNIT_FIELD_BYTES_2, 1, GetByteValue(UNIT_FIELD_BYTES_2, 1));
// FIXME: hack, speed must be set only at follow
if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
minion->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
// Ghoul pets have energy instead of mana (is anywhere better place for this code?)
if (minion->IsPetGhoul() || minion->GetEntry() == 24207 /*ENTRY_ARMY_OF_THE_DEAD*/)
minion->setPowerType(POWER_ENERGY);
@@ -14268,7 +14263,17 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
{
// Set creature speed rate
if (GetTypeId() == TYPEID_UNIT)
speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
{
if (IsPet() && ToPet()->isControlled() && IsControlledByPlayer())
{
// contant value for player pets
speed *= 1.15f;
}
else
{
speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
}
}
// Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
/// @todo possible affect only on MOVE_RUN
@@ -15397,7 +15402,7 @@ void Unit::SetHealth(uint32 val)
SetUInt32Value(UNIT_FIELD_HEALTH, val);
// mobs that are now or were below 30% need to update their speed
if (GetTypeId() == TYPEID_UNIT && (prevHealthPct < 30.0 || HealthBelowPct(30)))
if (GetTypeId() == TYPEID_UNIT && !(IsPet() && ToPet()->isControlled() && IsControlledByPlayer()) && (prevHealthPct < 30.0 || HealthBelowPct(30)))
{
UpdateSpeed(MOVE_RUN, false);
}
@@ -15905,7 +15910,10 @@ bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates new
{
WorldPacket data;
creature->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spell_id, cooldown);
creature->GetCharmer()->ToPlayer()->SendDirectMessage(&data);
if (creature->GetCharmer() && creature->GetCharmer()->IsPlayer())
{
creature->GetCharmer()->ToPlayer()->SendDirectMessage(&data);
}
}
}, 500ms);
}
@@ -18586,15 +18594,15 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
// Charmer stop charming
if (playerCharmer)
{
playerCharmer->StopCastingCharm();
playerCharmer->StopCastingBindSight();
playerCharmer->StopCastingCharm(aurApp ? aurApp->GetBase() : nullptr);
playerCharmer->StopCastingBindSight(aurApp ? aurApp->GetBase() : nullptr);
}
// Charmed stop charming
if (GetTypeId() == TYPEID_PLAYER)
{
ToPlayer()->StopCastingCharm();
ToPlayer()->StopCastingBindSight();
ToPlayer()->StopCastingCharm(aurApp ? aurApp->GetBase() : nullptr);
ToPlayer()->StopCastingBindSight(aurApp ? aurApp->GetBase() : nullptr);
}
// StopCastingCharm may remove a possessed pet?
@@ -18706,8 +18714,11 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(GameTime::GetGameTime().count())); // cast can't be helped
}
}
GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, GetFollowAngle());
playerCharmer->CharmSpellInitialize();
if (playerCharmer->m_seer != this)
{
GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, GetFollowAngle());
playerCharmer->CharmSpellInitialize();
}
break;
default:
break;
@@ -19979,17 +19990,27 @@ void Unit::_ExitVehicle(Position const* exitPosition)
pos = *exitPosition;
// HACK
if (vehicle->GetVehicleInfo()->m_ID == 380) // Kologarn right arm
pos.Relocate(1776.0f, -24.0f, 448.75f, 0.0f);
else if (vehicle->GetVehicleInfo()->m_ID == 91) // Helsman's Ship
pos.Relocate(2802.18f, 7054.91f, -0.6f, 4.67f);
else if (vehicle->GetVehicleInfo()->m_ID == 349) // AT Mounts, dismount to the right
VehicleEntry const* vehicleInfo = vehicle->GetVehicleInfo();
if (vehicleInfo)
{
float x = pos.GetPositionX() + 2.0f * cos(pos.GetOrientation() - M_PI / 2.0f);
float y = pos.GetPositionY() + 2.0f * std::sin(pos.GetOrientation() - M_PI / 2.0f);
float z = GetMapHeight(x, y, pos.GetPositionZ());
if (z > INVALID_HEIGHT)
pos.Relocate(x, y, z);
if (vehicleInfo->m_ID == 380) // Kologarn right arm
{
pos.Relocate(1776.0f, -24.0f, 448.75f, 0.0f);
}
else if (vehicleInfo->m_ID == 91) // Helsman's Ship
{
pos.Relocate(2802.18f, 7054.91f, -0.6f, 4.67f);
}
else if (vehicleInfo->m_ID == 349) // AT Mounts, dismount to the right
{
float x = pos.GetPositionX() + 2.0f * cos(pos.GetOrientation() - M_PI / 2.0f);
float y = pos.GetPositionY() + 2.0f * std::sin(pos.GetOrientation() - M_PI / 2.0f);
float z = GetMapHeight(x, y, pos.GetPositionZ());
if (z > INVALID_HEIGHT)
{
pos.Relocate(x, y, z);
}
}
}
AddUnitState(UNIT_STATE_MOVE);
@@ -20009,7 +20030,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
}
// xinef: hack for flameleviathan seat vehicle
if (vehicle->GetVehicleInfo()->m_ID != 341)
if (!vehicleInfo || vehicleInfo->m_ID != 341)
{
Movement::MoveSplineInit init(this);
init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
@@ -20031,16 +20052,18 @@ void Unit::_ExitVehicle(Position const* exitPosition)
}
// xinef: move fall, should we support all creatures that exited vehicle in air? Currently Quest Drag and Drop only, Air Assault quest
if (GetTypeId() == TYPEID_UNIT && !CanFly() &&
(vehicle->GetVehicleInfo()->m_ID == 113 || vehicle->GetVehicleInfo()->m_ID == 8 || vehicle->GetVehicleInfo()->m_ID == 290 || vehicle->GetVehicleInfo()->m_ID == 298))
if (GetTypeId() == TYPEID_UNIT && !CanFly() && vehicleInfo && (vehicleInfo->m_ID == 113 || vehicleInfo->m_ID == 8 || vehicleInfo->m_ID == 290 || vehicleInfo->m_ID == 298))
{
GetMotionMaster()->MoveFall();
//GetMotionMaster()->MoveFall(); // Enable this once passenger positions are calculater properly (see above)
}
if ((!player || !(player->GetDelayedOperations() & DELAYED_VEHICLE_TELEPORT)) && vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION))
if (((Minion*)vehicleBase)->GetOwner() == this)
{
if (vehicle->GetVehicleInfo()->m_ID != 349)
if (!vehicleInfo || vehicleInfo->m_ID != 349)
{
vehicle->Dismiss();
}
else if (vehicleBase->GetTypeId() == TYPEID_UNIT)
{
vehicle->Uninstall();
+3 -1
View File
@@ -1337,7 +1337,7 @@ public:
void Update(uint32 time) override;
void setAttackTimer(WeaponAttackType type, int32 time) { m_attackTimer[type] = time; }
void setAttackTimer(WeaponAttackType type, int32 time) { m_attackTimer[type] = time; } /// @todo - Look to convert to std::chrono
void resetAttackTimer(WeaponAttackType type = BASE_ATTACK);
[[nodiscard]] int32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; }
[[nodiscard]] bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] <= 0; }
@@ -2467,6 +2467,8 @@ public:
bool m_cannotReachTarget;
[[nodiscard]] uint32 GetOldFactionId() const { return _oldFactionId; }
protected:
explicit Unit (bool isWorldObject);
+80
View File
@@ -8204,6 +8204,81 @@ void ObjectMgr::AddReservedPlayerName(std::string const& name)
}
}
void ObjectMgr::LoadProfanityPlayersNames()
{
uint32 oldMSTime = getMSTime();
_profanityNamesStore.clear(); // need for reload case
QueryResult result = CharacterDatabase.Query("SELECT name FROM profanity_name");
if (!result)
{
LOG_WARN("server.loading", ">> Loaded 0 profanity player names. DB table `profanity_name` is empty!");
LOG_INFO("server.loading", " ");
return;
}
uint32 count = 0;
Field* fields;
do
{
fields = result->Fetch();
std::string name = fields[0].Get<std::string>();
std::wstring wstr;
if (!Utf8toWStr (name, wstr))
{
LOG_ERROR("sql.sql", "Table `profanity_name` have invalid name: {}", name);
continue;
}
wstrToLower(wstr);
_profanityNamesStore.insert(wstr);
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded {} profanity player names in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
LOG_INFO("server.loading", " ");
}
bool ObjectMgr::IsProfanityName(std::string_view name) const
{
// pussywizard
if (name.size() >= 2 && (name[name.size() - 2] == 'G' || name[name.size() - 2] == 'g') && (name[name.size() - 1] == 'M' || name[name.size() - 1] == 'm'))
return true;
std::wstring wstr;
if (!Utf8toWStr (name, wstr))
return false;
wstrToLower(wstr);
return _profanityNamesStore.find(wstr) != _profanityNamesStore.end();
}
void ObjectMgr::AddProfanityPlayerName(std::string const& name)
{
if (!IsProfanityName(name))
{
std::wstring wstr;
if (!Utf8toWStr(name, wstr))
{
LOG_ERROR("server", "Could not add invalid name to profanity player names: {}", name);
return;
}
wstrToLower(wstr);
_profanityNamesStore.insert(wstr);
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PROFANITY_PLAYER_NAME);
stmt->SetData(0, name);
CharacterDatabase.Execute(stmt);
}
}
enum LanguageType
{
LT_BASIC_LATIN = 0x0000,
@@ -8311,6 +8386,11 @@ uint8 ObjectMgr::CheckPlayerName(std::string_view name, bool create)
return CHAR_NAME_RESERVED;
}
if (sObjectMgr->IsProfanityName(name))
{
return CHAR_NAME_PROFANE;
}
// Check for Reserved Name from DBC
if (sWorld->getBoolConfig(CONFIG_STRICT_NAMES_RESERVED))
{
+9
View File
@@ -1338,6 +1338,11 @@ public:
[[nodiscard]] bool IsReservedName(std::string_view name) const;
void AddReservedPlayerName(std::string const& name);
// profanity names
void LoadProfanityPlayersNames();
[[nodiscard]] bool IsProfanityName(std::string_view name) const;
void AddProfanityPlayerName(std::string const& name);
// name with valid structure and symbols
static uint8 CheckPlayerName(std::string_view name, bool create = false);
static PetNameInvalidReason CheckPetName(std::string_view name);
@@ -1507,6 +1512,10 @@ private:
typedef std::set<std::wstring> ReservedNamesContainer;
ReservedNamesContainer _reservedNamesStore;
//character profanity names
typedef std::set<std::wstring> ProfanityNamesContainer;
ReservedNamesContainer _profanityNamesStore;
GameTeleContainer _gameTeleStore;
ScriptNameContainer _scriptNamesStore;
@@ -860,7 +860,7 @@ namespace Acore
AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {}
bool operator()(Unit* u)
{
if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u) &&
if (u->IsAlive() && !u->IsCritter() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u) &&
(i_funit->GetTypeId() != TYPEID_UNIT || !i_funit->ToCreature()->IsAvoidingAOE())) // pussywizard
return true;
else
+1 -1
View File
@@ -1184,7 +1184,7 @@ void Guild::OnPlayerStatusChange(Player* player, uint32 flag, bool state)
bool Guild::SetName(std::string_view const& name)
{
if (m_name == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
if (m_name == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || sObjectMgr->IsProfanityName(name) || !ObjectMgr::IsValidCharterName(name))
{
return false;
}
+4 -1
View File
@@ -409,7 +409,10 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
}
//Player is not looking at loot list, he doesn't need to see updates on the loot list
loot->RemoveLooter(player->GetGUID());
if (!lguid.IsItem())
{
loot->RemoveLooter(player->GetGUID());
}
}
void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData)
-4
View File
@@ -289,10 +289,6 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData)
if (unit->GetNpcFlags() == UNIT_NPC_FLAG_NONE)
return;
// xinef: do not allow to open gossip when npc is in combat
if (unit->GetNpcFlags() == UNIT_NPC_FLAG_GOSSIP && unit->IsInCombat()) // should work on all flags?
return;
// set faction visible if needed
if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction()))
_player->GetReputationMgr().SetVisible(factionTemplateEntry);
+6
View File
@@ -861,6 +861,12 @@ void WorldSession::HandlePetRename(WorldPacket& recvData)
return;
}
if (sObjectMgr->IsProfanityName(name))
{
SendPetNameInvalid(PET_NAME_PROFANE, name, nullptr);
return;
}
pet->SetName(name);
Unit* owner = pet->GetOwner();
@@ -137,7 +137,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
return;
}
if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
if (sObjectMgr->IsReservedName(name) || sObjectMgr->IsProfanityName(name) || !ObjectMgr::IsValidCharterName(name))
{
Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_INVALID, name);
return;
@@ -150,7 +150,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
return;
}
if (sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
if (sObjectMgr->IsReservedName(name) || sObjectMgr->IsProfanityName(name) || !ObjectMgr::IsValidCharterName(name))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
return;
@@ -351,7 +351,7 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket& recvData)
Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_EXISTS_S, newName);
return;
}
if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName))
if (sObjectMgr->IsReservedName(newName) || sObjectMgr->IsProfanityName(newName) || !ObjectMgr::IsValidCharterName(newName))
{
Guild::SendCommandResult(this, GUILD_COMMAND_CREATE, ERR_GUILD_NAME_INVALID, newName);
return;
@@ -364,7 +364,7 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket& recvData)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
return;
}
if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName))
if (sObjectMgr->IsReservedName(newName) || sObjectMgr->IsProfanityName(newName) || !ObjectMgr::IsValidCharterName(newName))
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_INVALID);
return;
@@ -612,6 +612,35 @@ void InstanceScript::DoCastSpellOnPlayers(uint32 spell)
player->CastSpell(player, spell, true);
}
void InstanceScript::DoCastSpellOnPlayer(Player* player, uint32 spell, bool includePets /*= false*/, bool includeControlled /*= false*/)
{
if (!player)
return;
player->CastSpell(player, spell, true);
if (!includePets)
return;
for (uint8 itr2 = 0; itr2 < MAX_SUMMON_SLOT; ++itr2)
{
ObjectGuid summonGUID = player->m_SummonSlot[itr2];
if (!summonGUID.IsEmpty())
if (Creature* summon = instance->GetCreature(summonGUID))
summon->CastSpell(player, spell, true);
}
if (!includeControlled)
return;
for (auto itr2 = player->m_Controlled.begin(); itr2 != player->m_Controlled.end(); ++itr2)
{
if (Unit* controlled = *itr2)
if (controlled->IsInWorld() && controlled->GetTypeId() == TYPEID_UNIT)
controlled->CastSpell(player, spell, true);
}
}
bool InstanceScript::CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/ /*= nullptr*/, uint32 /*miscvalue1*/ /*= 0*/)
{
LOG_ERROR("scripts.ai", "Achievement system call InstanceScript::CheckAchievementCriteriaMeet but instance script for map {} not have implementation for achievement criteria {}",
@@ -220,6 +220,9 @@ public:
// Cast spell on all players in instance
void DoCastSpellOnPlayers(uint32 spell);
// Cast spell on player
void DoCastSpellOnPlayer(Player* player, uint32 spell, bool includePets /*= false*/, bool includeControlled /*= false*/);
// Return wether server allow two side groups or not
bool ServerAllowsTwoSideGroups() { return sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP); }
+1
View File
@@ -190,6 +190,7 @@ uint32 LootStore::LoadLootTable()
// Looking for the template of the entry
// often entries are put together
// cppcheck-suppress eraseDereference
if (m_LootTemplates.empty() || tab->first != entry)
{
// Searching the template (in case template Id changed)
+1 -1
View File
@@ -218,7 +218,7 @@ enum AcoreStrings
LANG_GRID_POSITION = 178,
// 179-185 used in other client versions
LANG_TRANSPORT_POSITION = 186,
// 187
LANG_PROFANITY_NAME = 187,
LANG_2FA_SECRET_TOO_LONG = 188,
LANG_2FA_SECRET_INVALID = 189,
LANG_2FA_SECRET_SET_COMPLETE = 190,
@@ -296,7 +296,13 @@ static Optional<float> GetVelocity(Unit* owner, Unit* target, G3D::Vector3 const
if (!owner->IsInCombat() && !owner->IsVehicle() && !owner->HasUnitFlag(UNIT_FLAG_POSSESSED) &&
(owner->IsPet() || owner->IsGuardian() || owner->GetGUID() == target->GetCritterGUID() || owner->GetCharmerOrOwnerGUID() == target->GetGUID()))
{
UnitMoveType moveType = Movement::SelectSpeedType(target->GetUnitMovementFlags());
uint32 moveFlags = target->GetUnitMovementFlags();
if (target->movespline->isWalking())
{
moveFlags |= MOVEMENTFLAG_WALKING;
}
UnitMoveType moveType = Movement::SelectSpeedType(moveFlags);
speed = std::max(target->GetSpeed(moveType), owner->GetSpeed(moveType));
if (playerPet)
@@ -503,8 +509,8 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
init.SetWalk(target->IsWalking());
if (Optional<float> velocity = GetVelocity(owner, target, i_path->GetActualEndPosition(), owner->IsGuardian() && target->GetTypeId() == TYPEID_PLAYER))
init.SetWalk(target->IsWalking() || target->movespline->isWalking());
if (Optional<float> velocity = GetVelocity(owner, target, i_path->GetActualEndPosition(), owner->IsGuardian()))
init.SetVelocity(*velocity);
init.Launch();
}
+6 -2
View File
@@ -1102,8 +1102,12 @@ void WorldSession::ReadMovementInfo(WorldPacket& data, MovementInfo* mi)
e.g. aerial combat.
*/
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER && !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) && !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED),
MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY);
if (mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER && !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) && !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
{
// Inform the client we can no longer fly, which is required if data mismatches for some reason
// Like flight auras being removed but the client still sends flight movement packets.
GetPlayer()->SetCanFly(false);
}
//! Cannot fly and fall at the same time
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY) && mi->HasMovementFlag(MOVEMENTFLAG_FALLING),
@@ -6032,13 +6032,6 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
Unit::Kill(target, target);
return;
}
// Spellcloth
case 31373:
{
// Summon Elemental after create item
target->SummonCreature(17870, 0, 0, 0, target->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
return;
}
// Eye of Grillok
case 38495:
triggerSpellId = 38530;
+1 -1
View File
@@ -131,7 +131,7 @@ public:
int32 CalcMaxDuration() const { return CalcMaxDuration(GetCaster()); }
int32 CalcMaxDuration(Unit* caster) const;
int32 GetDuration() const { return m_duration; }
void SetDuration(int32 duration, bool withMods = false);
void SetDuration(int32 duration, bool withMods = false); /// @todo - Look to convert to std::chrono
void RefreshDuration(bool withMods = false);
void RefreshTimers(bool periodicReset = false);
void RefreshTimersWithMods();
+15 -6
View File
@@ -3352,6 +3352,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
// some spell specific modifiers
float totalDamagePercentMod = 100.0f; // applied to final bonus+weapon damage
int32 spell_bonus = 0; // bonus specific for spell
bool normalized = false;
switch (m_spellInfo->SpellFamilyName)
{
@@ -3438,6 +3439,18 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()));
}
switch (m_spellInfo->Id)
{
case 20424: // Seal of Command
case 42463: // Seal of Vengeance
case 53739: // Seal of Corruption
case 53385: // Divine Storm
normalized = true;
break;
default:
break;
}
break;
}
case SPELLFAMILY_SHAMAN:
@@ -3557,14 +3570,9 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
}
}
bool normalized = false;
float weaponDamagePercentMod = 100.0f;
int32 fixed_bonus = 0;
// xinef: Divine Storm deals normalized damage
if (m_spellInfo->Id == 53385)
normalized = true;
for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
{
switch (m_spellInfo->Effects[j].Effect)
@@ -4939,7 +4947,8 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
m_caster->ToPlayer()->SetFallInformation(GameTime::GetGameTime().count(), m_caster->GetPositionZ());
ObjectGuid targetGUID = ObjectGuid::Empty;
if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->GetTarget() == unitTarget->GetGUID())
if (!m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) && !m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER &&
m_caster->GetTarget() == unitTarget->GetGUID())
{
targetGUID = unitTarget->GetGUID();
}
@@ -4470,6 +4470,18 @@ void SpellMgr::LoadSpellInfoCorrections()
{
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
});
// Game In Session
ApplySpellFix({ 39331 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_APPLY_AURA;
spellInfo->Attributes |= SPELL_ATTR0_NO_AURA_CANCEL;
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP;
});
// Death Ray Warning Visual, Death Ray Damage Visual
ApplySpellFix({ 63882, 63886 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx5 |= SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
+15 -10
View File
@@ -154,6 +154,11 @@ bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 le
}
}
bool Warden::IsInitialized()
{
return _initialized;
}
union keyData
{
std::array<uint8, 20> bytes;
@@ -240,28 +245,28 @@ void Warden::ApplyPenalty(uint16 checkId, std::string const& reason)
{
if (Player const* plr = _session->GetPlayer())
{
std::string const reportFormat = "Player %s (guid %u, account id: %u) failed warden %u check (%s). Action: %s";
reportMsg = Acore::StringFormat(reportFormat, plr->GetName().c_str(), plr->GetGUID().GetCounter(), _session->GetAccountId(),
checkId, ((checkData && !checkData->Comment.empty()) ? checkData->Comment.c_str() : "<warden comment is not set>"),
GetWardenActionStr(action).c_str());
std::string const reportFormat = "Player {} (guid {}, account id: {}) failed warden {} check ({}). Action: {}";
reportMsg = Acore::StringFormatFmt(reportFormat, plr->GetName(), plr->GetGUID().GetCounter(), _session->GetAccountId(),
checkId, ((checkData && !checkData->Comment.empty()) ? checkData->Comment : "<warden comment is not set>"),
GetWardenActionStr(action));
}
else
{
std::string const reportFormat = "Account id: %u failed warden %u check. Action: %s";
reportMsg = Acore::StringFormat(reportFormat, _session->GetAccountId(), checkId, GetWardenActionStr(action).c_str());
std::string const reportFormat = "Account id: {} failed warden {} check. Action: {}";
reportMsg = Acore::StringFormatFmt(reportFormat, _session->GetAccountId(), checkId, GetWardenActionStr(action));
}
}
else
{
if (Player const* plr = _session->GetPlayer())
{
std::string const reportFormat = "Player %s (guid %u, account id: %u) triggered warden penalty by reason: %s. Action: %s";
reportMsg = Acore::StringFormat(reportFormat, plr->GetName().c_str(), plr->GetGUID().GetCounter(), _session->GetAccountId(), causeMsg.c_str(), GetWardenActionStr(action).c_str());
std::string const reportFormat = "Player {} (guid {}, account id: {}) triggered warden penalty by reason: {}. Action: {}";
reportMsg = Acore::StringFormatFmt(reportFormat, plr->GetName(), plr->GetGUID().GetCounter(), _session->GetAccountId(), causeMsg, GetWardenActionStr(action));
}
else
{
std::string const reportFormat = "Account id: %u failed warden %u check. Action: %s";
reportMsg = Acore::StringFormat(reportFormat, _session->GetAccountId(), causeMsg.c_str(), GetWardenActionStr(action).c_str());
std::string const reportFormat = "Account id: {} failed warden {} check. Action: {}";
reportMsg = Acore::StringFormatFmt(reportFormat, _session->GetAccountId(), causeMsg, GetWardenActionStr(action));
}
}
+1
View File
@@ -115,6 +115,7 @@ public:
virtual void RequestHash() = 0;
virtual void HandleHashResult(ByteBuffer &buff) = 0;
virtual bool IsCheckInProgress() = 0;
virtual bool IsInitialized();
virtual void ForceChecks() = 0;
virtual void RequestChecks() = 0;
virtual void HandleData(ByteBuffer &buff) = 0;
+151 -143
View File
@@ -561,189 +561,197 @@ void WardenWin::RequestChecks()
void WardenWin::HandleData(ByteBuffer& buff)
{
if (!_interrupted)
LOG_DEBUG("warden", "Handle data");
_dataSent = false;
_clientResponseTimer = 0;
uint16 Length;
buff >> Length;
uint32 Checksum;
buff >> Checksum;
if (Length != (buff.size() - buff.rpos()))
{
LOG_DEBUG("warden", "Handle data");
buff.rfinish();
_dataSent = false;
_clientResponseTimer = 0;
uint16 Length;
buff >> Length;
uint32 Checksum;
buff >> Checksum;
if (Length != (buff.size() - buff.rpos()))
if (!_interrupted)
{
buff.rfinish();
ApplyPenalty(0, "Failed size checks in HandleData");
return;
}
if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
return;
}
if (!IsValidCheckSum(Checksum, buff.contents() + buff.rpos(), Length))
{
buff.rpos(buff.wpos());
LOG_DEBUG("warden", "CHECKSUM FAIL");
if (!_interrupted)
{
buff.rpos(buff.wpos());
LOG_DEBUG("warden", "CHECKSUM FAIL");
ApplyPenalty(0, "Failed checksum in HandleData");
}
return;
}
// TIMING_CHECK
{
uint8 result;
buff >> result;
/// @todo: test it.
if (result == 0x00)
{
LOG_DEBUG("warden", "TIMING CHECK FAIL result 0x00");
// ApplyPenalty(0, "TIMING CHECK FAIL result"); Commented out because of too many false postives. Mostly caused by client stutter.
return;
}
// TIMING_CHECK
uint32 newClientTicks;
buff >> newClientTicks;
uint32 ticksNow = GameTime::GetGameTimeMS().count();
uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
LOG_DEBUG("warden", "ServerTicks {}", ticksNow); // Now
LOG_DEBUG("warden", "RequestTicks {}", _serverTicks); // At request
LOG_DEBUG("warden", "Ticks {}", newClientTicks); // At response
LOG_DEBUG("warden", "Ticks diff {}", ourTicks - newClientTicks);
}
uint16 checkFailed = 0;
for (uint16 const checkId : _CurrentChecks)
{
WardenCheck const* rd = sWardenCheckMgr->GetWardenDataById(checkId);
// Custom payload should be loaded in if equal to over offset.
if (!rd && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
{
uint8 result;
buff >> result;
/// @todo: test it.
if (result == 0x00)
{
LOG_DEBUG("warden", "TIMING CHECK FAIL result 0x00");
// ApplyPenalty(0, "TIMING CHECK FAIL result"); Commented out because of too many false postives. Mostly caused by client stutter.
return;
}
uint32 newClientTicks;
buff >> newClientTicks;
uint32 ticksNow = GameTime::GetGameTimeMS().count();
uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks);
LOG_DEBUG("warden", "ServerTicks {}", ticksNow); // Now
LOG_DEBUG("warden", "RequestTicks {}", _serverTicks); // At request
LOG_DEBUG("warden", "Ticks {}", newClientTicks); // At response
LOG_DEBUG("warden", "Ticks diff {}", ourTicks - newClientTicks);
rd = &_payloadMgr.CachedChecks.at(checkId);
}
uint16 checkFailed = 0;
for (uint16 const checkId : _CurrentChecks)
uint8 const type = rd->Type;
switch (type)
{
WardenCheck const* rd = sWardenCheckMgr->GetWardenDataById(checkId);
case MEM_CHECK:
{
uint8 Mem_Result;
buff >> Mem_Result;
// Custom payload should be loaded in if equal to over offset.
if (!rd && checkId >= WardenPayloadMgr::WardenPayloadOffsetMin)
if (Mem_Result != 0)
{
rd = &_payloadMgr.CachedChecks.at(checkId);
LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId {} account Id {}", checkId, _session->GetAccountId());
checkFailed = checkId;
continue;
}
uint8 const type = rd->Type;
switch (type)
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
std::vector<uint8> result = rs->Result.ToByteVector(0, false);
if (memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0)
{
case MEM_CHECK:
{
uint8 Mem_Result;
buff >> Mem_Result;
if (Mem_Result != 0)
{
LOG_DEBUG("warden", "RESULT MEM_CHECK not 0x00, CheckId {} account Id {}", checkId, _session->GetAccountId());
checkFailed = checkId;
continue;
}
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
std::vector<uint8> result = rs->Result.ToByteVector(0, false);
if (memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0)
{
LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId {} account Id {}", checkId, _session->GetAccountId());
checkFailed = checkId;
buff.rpos(buff.rpos() + rd->Length);
continue;
}
LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId {} account Id {}", checkId, _session->GetAccountId());
checkFailed = checkId;
buff.rpos(buff.rpos() + rd->Length);
LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
break;
continue;
}
case PAGE_CHECK_A:
case PAGE_CHECK_B:
case DRIVER_CHECK:
case MODULE_CHECK:
buff.rpos(buff.rpos() + rd->Length);
LOG_DEBUG("warden", "RESULT MEM_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
break;
}
case PAGE_CHECK_A:
case PAGE_CHECK_B:
case DRIVER_CHECK:
case MODULE_CHECK:
{
uint8 const byte = 0xE9;
if (memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0)
{
uint8 const byte = 0xE9;
if (memcmp(buff.contents() + buff.rpos(), &byte, sizeof(uint8)) != 0)
{
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
{
LOG_DEBUG("warden", "RESULT PAGE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
}
if (type == MODULE_CHECK)
{
LOG_DEBUG("warden", "RESULT MODULE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
}
if (type == DRIVER_CHECK)
{
LOG_DEBUG("warden", "RESULT DRIVER_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
}
checkFailed = checkId;
buff.rpos(buff.rpos() + 1);
continue;
}
buff.rpos(buff.rpos() + 1);
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
{
LOG_DEBUG("warden", "RESULT PAGE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
LOG_DEBUG("warden", "RESULT PAGE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
}
else if (type == MODULE_CHECK)
if (type == MODULE_CHECK)
{
LOG_DEBUG("warden", "RESULT MODULE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
LOG_DEBUG("warden", "RESULT MODULE_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
}
else if (type == DRIVER_CHECK)
if (type == DRIVER_CHECK)
{
LOG_DEBUG("warden", "RESULT DRIVER_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
LOG_DEBUG("warden", "RESULT DRIVER_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
}
break;
checkFailed = checkId;
buff.rpos(buff.rpos() + 1);
continue;
}
case LUA_EVAL_CHECK:
buff.rpos(buff.rpos() + 1);
if (type == PAGE_CHECK_A || type == PAGE_CHECK_B)
{
uint8 const result = buff.read<uint8>();
if (result == 0)
{
buff.read_skip(buff.read<uint8>()); // discard attached string
}
LOG_DEBUG("warden", "LUA_EVAL_CHECK CheckId {} account Id {} got in-warden dummy response", checkId, _session->GetAccountId()/* , result */);
break;
LOG_DEBUG("warden", "RESULT PAGE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
}
case MPQ_CHECK:
else if (type == MODULE_CHECK)
{
uint8 Mpq_Result;
buff >> Mpq_Result;
if (Mpq_Result != 0)
{
LOG_DEBUG("warden", "RESULT MPQ_CHECK not 0x00 account id {}", _session->GetAccountId());
checkFailed = checkId;
continue;
}
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES) != 0) // SHA1
{
LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
checkFailed = checkId;
buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
continue;
}
buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId {} account Id {}", checkId, _session->GetAccountId());
break;
LOG_DEBUG("warden", "RESULT MODULE_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
}
else if (type == DRIVER_CHECK)
{
LOG_DEBUG("warden", "RESULT DRIVER_CHECK passed CheckId {} account Id {}", checkId, _session->GetAccountId());
}
break;
}
if (checkFailed > 0)
case LUA_EVAL_CHECK:
{
ApplyPenalty(checkFailed, "");
uint8 const result = buff.read<uint8>();
if (result == 0)
{
buff.read_skip(buff.read<uint8>()); // discard attached string
}
LOG_DEBUG("warden", "LUA_EVAL_CHECK CheckId {} account Id {} got in-warden dummy response", checkId, _session->GetAccountId()/* , result */);
break;
}
case MPQ_CHECK:
{
uint8 Mpq_Result;
buff >> Mpq_Result;
if (Mpq_Result != 0)
{
LOG_DEBUG("warden", "RESULT MPQ_CHECK not 0x00 account id {}", _session->GetAccountId());
checkFailed = checkId;
continue;
}
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES) != 0) // SHA1
{
LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId {} account Id {}", checkId, _session->GetAccountId());
checkFailed = checkId;
buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
continue;
}
buff.rpos(buff.rpos() + Acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
LOG_DEBUG("warden", "RESULT MPQ_CHECK passed, CheckId {} account Id {}", checkId, _session->GetAccountId());
break;
}
}
}
else
if (checkFailed > 0 && !_interrupted)
{
ApplyPenalty(checkFailed, "");
}
if (_interrupted)
{
LOG_DEBUG("warden", "Warden was interrupted by ForceChecks, ignoring results.");
+4 -1
View File
@@ -1912,9 +1912,12 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", "Loading Groups...");
sGroupMgr->LoadGroups();
LOG_INFO("server.loading", "Loading ReservedNames...");
LOG_INFO("server.loading", "Loading Reserved Names...");
sObjectMgr->LoadReservedPlayersNames();
LOG_INFO("server.loading", "Loading Profanity Names...");
sObjectMgr->LoadProfanityPlayersNames();
LOG_INFO("server.loading", "Loading GameObjects for Quests...");
sObjectMgr->LoadGameObjectForQuests();