Merge pull request #157 from azerothcore/master

Update
This commit is contained in:
bashermens
2026-01-22 17:27:50 +01:00
committed by GitHub
78 changed files with 1622 additions and 334 deletions
@@ -162,7 +162,7 @@ void AccountInfo::LoadResult(Field* fields)
Utf8ToUpperOnlyLatin(Login);
}
AuthSession::AuthSession(tcp::socket&& socket) :
AuthSession::AuthSession(IoContextTcpSocket&& socket) :
Socket(std::move(socket)), _status(STATUS_CHALLENGE), _build(0), _expversion(0) { }
void AuthSession::Start()
@@ -216,7 +216,7 @@ void AuthSession::CheckIpCallback(PreparedQueryResult result)
AsyncRead();
}
void AuthSession::ReadHandler()
SocketReadCallbackResult AuthSession::ReadHandler()
{
MessageBuffer& packet = GetReadBuffer();
@@ -234,7 +234,7 @@ void AuthSession::ReadHandler()
if (_status != itr->second.status)
{
CloseSocket();
return;
return SocketReadCallbackResult::Stop;
}
uint16 size = uint16(itr->second.packetSize);
@@ -248,7 +248,7 @@ void AuthSession::ReadHandler()
if (size > MAX_ACCEPTED_CHALLENGE_SIZE)
{
CloseSocket();
return;
return SocketReadCallbackResult::Stop;
}
}
@@ -258,13 +258,13 @@ void AuthSession::ReadHandler()
if (!(*this.*itr->second.handler)())
{
CloseSocket();
return;
return SocketReadCallbackResult::Stop;
}
packet.ReadCompleted(size);
}
AsyncRead();
return SocketReadCallbackResult::KeepReading;
}
void AuthSession::SendPacket(ByteBuffer& packet)
@@ -60,22 +60,22 @@ struct AccountInfo
AccountTypes SecurityLevel = SEC_PLAYER;
};
class AuthSession : public Socket<AuthSession>
class AuthSession final : public Socket<AuthSession>
{
typedef Socket<AuthSession> AuthSocket;
public:
static std::unordered_map<uint8, AuthHandler> InitHandlers();
AuthSession(tcp::socket&& socket);
AuthSession(IoContextTcpSocket&& socket);
void Start() override;
bool Update() override;
bool Update() final;
void SendPacket(ByteBuffer& packet);
protected:
void ReadHandler() override;
SocketReadCallbackResult ReadHandler() final;
private:
bool HandleLogonChallenge();
@@ -54,9 +54,9 @@ protected:
return threads;
}
static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex)
static void OnSocketAccept(IoContextTcpSocket&& sock, uint32 threadIndex)
{
Instance().OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex);
Instance().OnSocketOpen(std::move(sock), threadIndex);
}
};
@@ -18,18 +18,16 @@
#ifndef __RASESSION_H__
#define __RASESSION_H__
#include <boost/asio/ip/tcp.hpp>
#include "Socket.h"
#include <boost/asio/streambuf.hpp>
#include <future>
using boost::asio::ip::tcp;
const std::size_t bufferSize = 4096;
class RASession : public std::enable_shared_from_this<RASession>
{
public:
RASession(tcp::socket&& socket) :
RASession(IoContextTcpSocket&& socket) :
_socket(std::move(socket)), _commandExecuting(nullptr) { }
void Start();
@@ -47,7 +45,7 @@ private:
static void CommandPrint(void* callbackArg, std::string_view text);
static void CommandFinished(void* callbackArg, bool);
tcp::socket _socket;
IoContextTcpSocket _socket;
boost::asio::streambuf _readBuffer;
boost::asio::streambuf _writeBuffer;
std::promise<void>* _commandExecuting;
@@ -3296,6 +3296,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
target->ToUnit()->SetAnimTier(AnimTier(e.action.animTier.animTier));
break;
}
case SMART_ACTION_SET_GOSSIP_MENU:
{
for (WorldObject* target : targets)
{
if (Creature* creature = target->ToCreature())
{
creature->SetGossipMenuId(e.action.setGossipMenu.gossipMenuId);
LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_SET_GOSSIP_MENU: Creature {} set gossip menu to {}",
creature->GetGUID().ToString(), e.action.setGossipMenu.gossipMenuId);
}
}
break;
}
default:
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
@@ -885,6 +885,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_WORLD_SCRIPT: return sizeof(SmartAction::worldStateScript);
case SMART_ACTION_DISABLE_REWARD: return sizeof(SmartAction::reward);
case SMART_ACTION_SET_ANIM_TIER: return sizeof(SmartAction::animTier);
case SMART_ACTION_SET_GOSSIP_MENU: return sizeof(SmartAction::setGossipMenu);
case SMART_ACTION_DISMOUNT: return NO_PARAMS;
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
@@ -2040,6 +2041,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_MOVEMENT_PAUSE:
case SMART_ACTION_MOVEMENT_RESUME:
case SMART_ACTION_WORLD_SCRIPT:
case SMART_ACTION_SET_GOSSIP_MENU:
break;
default:
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
@@ -724,8 +724,9 @@ enum SMART_ACTION
SMART_ACTION_WORLD_SCRIPT = 237, // eventId, param
SMART_ACTION_DISABLE_REWARD = 238, // reputation 0/1, loot 0/1
SMART_ACTION_SET_ANIM_TIER = 239, // animtier
SMART_ACTION_SET_GOSSIP_MENU = 240, // gossipMenuId
SMART_ACTION_AC_END = 240, // placeholder
SMART_ACTION_AC_END = 241, // placeholder
};
enum class SmartActionSummonCreatureFlags
@@ -1510,6 +1511,11 @@ struct SmartAction
{
uint32 animTier;
} animTier;
struct
{
uint32 gossipMenuId;
} setGossipMenu;
};
};
@@ -52,6 +52,7 @@ BattlegroundSA::BattlegroundSA()
EndRoundTimer = 0s;
ShipsStarted = false;
Status = BG_SA_NOTSTARTED;
_nextShipIsEast = true;
for (uint8 i = 0; i < 6; i++)
GateStatus[i] = BG_SA_GATE_OK;
@@ -85,6 +86,7 @@ void BattlegroundSA::Init()
_notEvenAScratch[TEAM_HORDE] = true;
Status = BG_SA_WARMUP;
_relicClicked = false;
_nextShipIsEast = true;
}
bool BattlegroundSA::SetupBattleground()
@@ -181,6 +183,7 @@ bool BattlegroundSA::ResetObjs()
TotalTime = 0s;
ShipsStarted = false;
_nextShipIsEast = true;
//Graveyards!
for (uint8 i = 0; i < BG_SA_MAX_GY; i++)
@@ -574,10 +577,12 @@ void BattlegroundSA::TeleportToEntrancePosition(Player* player)
if (!ShipsStarted)
{
player->CastSpell(player, 12438, true);//Without this player falls before boat loads...
if (urand(0, 1))
if (_nextShipIsEast)
player->TeleportTo(MAP_STRAND_OF_THE_ANCIENTS, 2682.936f, -830.368f, 15.0f, 2.895f, 0);
else
player->TeleportTo(MAP_STRAND_OF_THE_ANCIENTS, 2577.003f, 980.261f, 15.0f, 0.807f, 0);
_nextShipIsEast = !_nextShipIsEast;
}
else
player->TeleportTo(MAP_STRAND_OF_THE_ANCIENTS, 1600.381f, -106.263f, 8.8745f, 3.78f, 0);
@@ -620,5 +620,7 @@ private:
// Achievement: Not Even a Scratch
bool _notEvenAScratch[PVP_TEAMS_COUNT];
/// Toggle for alternating player spawns between East and West ships (true = first/East ship, false = second/West ship)
bool _nextShipIsEast;
};
#endif
+67 -2
View File
@@ -328,7 +328,7 @@ HostileReference* ThreatContainer::SelectNextVictim(Creature* attacker, HostileR
Unit* cvUnit = currentVictim->getTarget();
if (!attacker->CanCreatureAttack(cvUnit)) // pussywizard: if currentVictim is not valid => don't compare the threat with it, just take the highest threat valid target
currentVictim = nullptr;
else if (cvUnit->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()) || cvUnit->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE) || cvUnit->HasUnitState(UNIT_STATE_CONFUSED)) // pussywizard: no 10%/30% if currentVictim is immune to damage or has auras breakable by damage
else if (!IsPreferredTarget(attacker, cvUnit)) // pussywizard: no 10%/30% if currentVictim is immune to damage or has auras breakable by damage
currentVictim = nullptr;
}
@@ -345,7 +345,7 @@ HostileReference* ThreatContainer::SelectNextVictim(Creature* attacker, HostileR
// pussywizard: don't go to threat comparison if this ref is immune to damage or has aura breakable on damage (second choice target)
// pussywizard: if this is the last entry on the threat list, then all targets are second choice, set bool to true and loop threat list again, ignoring this section
if (!noPriorityTargetFound && (target->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()) || target->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE) || target->HasUnitState(UNIT_STATE_CONFUSED) || target->HasAuraTypeWithCaster(SPELL_AURA_IGNORED, attacker->GetGUID())))
if (!noPriorityTargetFound && !IsPreferredTarget(attacker, target))
{
if (iter != lastRef)
{
@@ -394,6 +394,8 @@ HostileReference* ThreatContainer::SelectNextVictim(Creature* attacker, HostileR
}
else // pussywizard: no currentVictim, first passing all checks is chosen (highest threat, list is sorted)
{
// tie-breaker if multiple targets have the same threat: select closest target
currentRef = SelectNextVictimTieBreaker(attacker, iter, noPriorityTargetFound);
found = true;
break;
}
@@ -406,6 +408,69 @@ HostileReference* ThreatContainer::SelectNextVictim(Creature* attacker, HostileR
return currentRef;
}
// Helper for Tie-breakers
HostileReference* ThreatContainer::SelectNextVictimTieBreaker(Creature* attacker, ThreatContainer::StorageType::const_iterator currentIter, bool noPriorityTargetFound) const
{
HostileReference* bestRef = *currentIter;
float bestThreat = bestRef->GetThreat();
float shortestDistSq = attacker->GetExactDistSq(bestRef->getTarget());
auto tieIter = std::next(currentIter);
while (tieIter != iThreatList.end())
{
HostileReference* nextRef = *tieIter;
if (!nextRef)
{
++tieIter;
continue;
}
// Threatlist is sorted, so we can stop as soon as we find a lower threat
if (bestThreat - nextRef->GetThreat() > 0.01f)
break;
Unit* target = nextRef->getTarget();
if (!target)
{
++tieIter;
continue;
}
if (attacker->CanCreatureAttack(target) && (noPriorityTargetFound || IsPreferredTarget(attacker, target)))
{
float distSq = attacker->GetExactDistSq(target);
if (distSq < shortestDistSq)
{
bestRef = nextRef;
shortestDistSq = distSq;
}
}
++tieIter;
}
return bestRef;
}
// Helper for checking if a target is preferred (not immune, not confused, etc)
bool ThreatContainer::IsPreferredTarget(Creature* attacker, Unit* target) const
{
if (target->IsImmunedToDamageOrSchool(attacker->GetMeleeDamageSchoolMask()))
return false;
if (target->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE))
return false;
if (target->HasUnitState(UNIT_STATE_CONFUSED))
return false;
if (target->HasAuraTypeWithCaster(SPELL_AURA_IGNORED, attacker->GetGUID()))
return false;
return true;
}
//============================================================
//=================== ThreatMgr ==========================
//============================================================
+4
View File
@@ -156,6 +156,10 @@ public:
HostileReference* SelectNextVictim(Creature* attacker, HostileReference* currentVictim) const;
HostileReference* SelectNextVictimTieBreaker(Creature* attacker, ThreatContainer::StorageType::const_iterator currentIter, bool noPriorityTargetFound) const;
bool IsPreferredTarget(Creature* attacker, Unit* target) const;
void setDirty(bool isDirty) { iDirty = isDirty; }
[[nodiscard]] bool isDirty() const { return iDirty; }
+5 -5
View File
@@ -542,13 +542,13 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
condMeets = object->GetMap()->GetDifficulty() == ConditionValue1;
break;
}
case CONDITION_RANDOM_DUNGEON:
case CONDITION_PLAYER_QUEUED_RANDOM_DUNGEON:
{
if (Unit* unit = object->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
if (Player* player = unit->ToPlayer())
{
if (sLFGMgr->selectedRandomLfgDungeon(player->GetGUID()))
if (sLFGMgr->IsPlayerQueuedForRandomDungeon(player->GetGUID()))
{
if (!ConditionValue1)
condMeets = true;
@@ -803,7 +803,7 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
case CONDITION_CHARMED:
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
break;
case CONDITION_RANDOM_DUNGEON:
case CONDITION_PLAYER_QUEUED_RANDOM_DUNGEON:
mask |= GRID_MAP_TYPE_MASK_PLAYER;
break;
case CONDITION_WORLD_SCRIPT:
@@ -2486,7 +2486,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond)
return false;
}
break;
case CONDITION_RANDOM_DUNGEON:
case CONDITION_PLAYER_QUEUED_RANDOM_DUNGEON:
if (cond->ConditionValue1 > 1)
{
LOG_ERROR("sql.sql", "RandomDungeon condition has useless data in value1 ({}).", cond->ConditionValue1);
+1 -1
View File
@@ -88,7 +88,7 @@ enum ConditionTypes
CONDITION_HAS_AURA_TYPE = 102, // aura_type 0 0 true if has aura type
CONDITION_WORLD_SCRIPT = 103, // conditionId state 0 true if WorldState::IsConditionFulfilled returns true
CONDITION_AI_DATA = 104, // dataId value 0 true if AI::GetData returns value
CONDITION_RANDOM_DUNGEON = 105, // difficulty (0 = any) 0 0 true if player is queued for a random dungeon via RDF (param1 = Difficulty)
CONDITION_PLAYER_QUEUED_RANDOM_DUNGEON = 105, // checkDifficulty difficulty 0 true if player is queued for a random dungeon via RDF
CONDITION_AC_END = 106 // placeholder
};
@@ -139,4 +139,13 @@ namespace lfg
return m_KicksLeft;
}
void LfgGroupData::AddRandomQueuedPlayer(ObjectGuid guid)
{
m_RandomQueuedPlayers.insert(guid);
}
[[nodiscard]] bool LfgGroupData::IsRandomQueuedPlayer(ObjectGuid guid) const
{
return m_RandomQueuedPlayers.contains(guid);
}
} // namespace lfg
@@ -37,6 +37,8 @@ namespace lfg
void SetState(LfgState state);
void RestoreState();
void AddPlayer(ObjectGuid guid);
void AddRandomQueuedPlayer(ObjectGuid guid);
[[nodiscard]] bool IsRandomQueuedPlayer(ObjectGuid guid) const;
uint8 RemovePlayer(ObjectGuid guid);
void RemoveAllPlayers();
void SetLeader(ObjectGuid guid);
@@ -66,6 +68,7 @@ namespace lfg
LfgState m_OldState; ///< Old State
ObjectGuid m_Leader; ///< Leader GUID
LfgGuidSet m_Players; ///< Players in group
LfgGuidSet m_RandomQueuedPlayers; ///< Players that queued for random dungeon
// Dungeon
uint32 m_Dungeon; ///< Dungeon entry
bool _isLFGGroup;
+20
View File
@@ -2583,6 +2583,18 @@ namespace lfg
GroupsStore[gguid].AddPlayer(guid);
}
void LFGMgr::AddPlayerQueuedForRandomDungeonToGroup(ObjectGuid gguid, ObjectGuid guid)
{
const LfgDungeonSet& dungeons = GetSelectedDungeons(guid);
if (dungeons.empty())
return;
uint32 dungeonId = *dungeons.begin();
LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId);
if (dungeon && (dungeon->type == LFG_TYPE_RANDOM))
GroupsStore[gguid].AddRandomQueuedPlayer(guid);
}
void LFGMgr::SetLeader(ObjectGuid gguid, ObjectGuid leader)
{
GroupsStore[gguid].SetLeader(leader);
@@ -2839,4 +2851,12 @@ namespace lfg
sDisableMgr->IsDisabledFor(DISABLE_TYPE_LFG_MAP, mapId, nullptr);
}
bool LFGMgr::IsPlayerQueuedForRandomDungeon(ObjectGuid guid)
{
auto gguid = GetGroup(guid);
if (!gguid)
return false;
return GroupsStore[gguid].IsRandomQueuedPlayer(guid);
}
} // namespace lfg
+3
View File
@@ -506,6 +506,9 @@ namespace lfg
uint8 RemovePlayerFromGroup(ObjectGuid gguid, ObjectGuid guid);
/// Adds player to group
void AddPlayerToGroup(ObjectGuid gguid, ObjectGuid guid);
/// Store player that selected random queue to group
void AddPlayerQueuedForRandomDungeonToGroup(ObjectGuid gguid, ObjectGuid guid);
bool IsPlayerQueuedForRandomDungeon(ObjectGuid guid);
/// Xinef: Set Random Players Count
void SetRandomPlayersCount(ObjectGuid guid, uint8 count);
/// Xinef: Get Random Players Count
@@ -187,6 +187,7 @@ namespace lfg
sLFGMgr->SetGroup(guid, gguid);
sLFGMgr->AddPlayerToGroup(gguid, guid);
sLFGMgr->AddPlayerQueuedForRandomDungeonToGroup(gguid, guid);
// pussywizard: after all necessary actions handle raid browser
if (sLFGMgr->GetState(guid) == LFG_STATE_RAIDBROWSER)
@@ -265,7 +265,7 @@ Creature::Creature(): Unit(), MovableMapObject(), m_groupLootTimer(0), lootingGr
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500),
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_alreadyCallForHelp(false), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), _gossipMenuId(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f),_sparringPct(0.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_lastLeashExtensionTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
{
@@ -204,6 +204,8 @@ public:
[[nodiscard]] CreatureTemplate const* GetCreatureTemplate() const { return m_creatureInfo; }
[[nodiscard]] CreatureData const* GetCreatureData() const { return m_creatureData; }
[[nodiscard]] uint32 GetGossipMenuId() const { return _gossipMenuId ? _gossipMenuId : GetCreatureTemplate()->GossipMenuId; }
void SetGossipMenuId(uint32 gossipMenuId) { _gossipMenuId = gossipMenuId; }
void SetDetectionDistance(float dist){ m_detectionDistance = dist; }
[[nodiscard]] CreatureAddon const* GetCreatureAddon() const;
@@ -478,6 +480,7 @@ protected:
SpellSchoolMask m_meleeDamageSchoolMask;
uint32 m_originalEntry;
uint32 _gossipMenuId;
bool m_moveInLineOfSightDisabled;
bool m_moveInLineOfSightStrictlyDisabled;
+3 -6
View File
@@ -1642,12 +1642,9 @@ void Player::ProcessDelayedOperations()
if (m_DelayedOperations & DELAYED_SAVE_PLAYER)
SaveToDB(false, false);
if (m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
{
Aura* aura = GetAura(26013);
if (!aura || aura->GetDuration() <= 900000)
if ((m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
&& !GetAura(26013))
CastSpell(this, 26013, true);
}
if (m_DelayedOperations & DELAYED_BG_MOUNT_RESTORE)
{
@@ -14378,7 +14375,7 @@ bool Player::CanSeeVendor(Creature const* creature) const
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(this), const_cast<Creature*>(creature), conditions))
return false;
uint32 const menuId = creature->GetCreatureTemplate()->GossipMenuId;
uint32 const menuId = creature->GetGossipMenuId();
if (!AnyVendorOptionAvailable(menuId, creature))
return false;
@@ -429,7 +429,7 @@ uint32 Player::GetDefaultGossipMenuForSource(WorldObject* source)
switch (source->GetTypeId())
{
case TYPEID_UNIT:
return source->ToCreature()->GetCreatureTemplate()->GossipMenuId;
return source->ToCreature()->GetGossipMenuId();
case TYPEID_GAMEOBJECT:
return source->ToGameObject()->GetGOInfo()->GetGossipMenuId();
default:
+12 -12
View File
@@ -2148,7 +2148,7 @@ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit const* victim, co
float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim)
{
float victimResistance = float(victim->GetResistance(schoolMask));
float victimResistance = static_cast<float>(victim->GetResistance(schoolMask));
if (owner)
{
// Xinef: pets inherit 100% of masters penetration
@@ -2156,28 +2156,28 @@ float Unit::GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMa
Player const* player = owner->GetSpellModOwner();
if (player && owner->GetEntry() != WORLD_TRIGGER)
{
victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
victimResistance -= float(player->GetSpellPenetrationItemMod());
victimResistance += static_cast<float>(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
victimResistance -= static_cast<float>(player->GetSpellPenetrationItemMod());
}
else
victimResistance += float(owner->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
victimResistance += static_cast<float>(owner->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
}
victimResistance = std::max(victimResistance, 0.0f);
if (owner)
victimResistance += std::max((float(victim->GetLevel()) - float(owner->GetLevel())) * 5.0f, 0.0f);
victimResistance += std::max(static_cast<float>(victim->GetLevel() - owner->GetLevel()) * 5.0f, 0.0f);
static uint32 const BOSS_LEVEL = 83;
static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
uint32 level = victim->GetLevel();
float level = static_cast<float>(victim->GetLevel());
float resistanceConstant = 0.0f;
if (level == BOSS_LEVEL)
resistanceConstant = BOSS_RESISTANCE_CONSTANT;
if (level > 60.0f)
resistanceConstant = 150.0f + (level - 60.0f) * (level - 67.5f);
else if (level > 20.0f)
resistanceConstant = 50.0f + (level - 20.0f) * 2.5f;
else
resistanceConstant = level * 5.0f;
resistanceConstant = 50.0f;
return victimResistance / (victimResistance + resistanceConstant);
return std::min(victimResistance / (victimResistance + resistanceConstant), 0.75f);
}
void Unit::CalcAbsorbResist(DamageInfo& dmgInfo, bool Splited)
+3
View File
@@ -602,7 +602,10 @@ void WorldSession::HandleSellItemOpcode(WorldPackets::Item::SellItem& packet)
if (pItem)
{
if (!sScriptMgr->OnPlayerCanSellItem(_player, pItem, creature))
{
_player->SendSellError(SELL_ERR_CANT_SELL_ITEM, creature, packet.ItemGuid, 0);
return;
}
// prevent sell not owner item
if (_player->GetGUID() != pItem->GetOwnerGUID())
+1 -1
View File
@@ -179,7 +179,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData)
if (!sScriptMgr->OnGossipHello(_player, unit))
{
// _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID());
_player->PrepareGossipMenu(unit, unit->GetCreatureTemplate()->GossipMenuId, true);
_player->PrepareGossipMenu(unit, unit->GetGossipMenuId(), true);
_player->SendPreparedGossip(unit);
}
unit->AI()->sGossipHello(_player);
+1 -1
View File
@@ -101,7 +101,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket& recvData)
if (sScriptMgr->OnGossipHello(_player, creature))
return;
_player->PrepareGossipMenu(creature, creature->GetCreatureTemplate()->GossipMenuId, true);
_player->PrepareGossipMenu(creature, creature->GetGossipMenuId(), true);
_player->SendPreparedGossip(creature);
creature->AI()->sGossipHello(_player);
@@ -436,7 +436,7 @@ static Optional<float> GetVelocity(Unit* owner, Unit* target, G3D::Vector3 const
(owner->IsPet() || owner->IsGuardian() || owner->GetGUID() == target->GetCritterGUID() || owner->GetCharmerOrOwnerGUID() == target->GetGUID()))
{
uint32 moveFlags = target->GetUnitMovementFlags();
if (target->movespline->isWalking())
if (target->IsWalking())
{
moveFlags |= MOVEMENTFLAG_WALKING;
}
@@ -635,7 +635,7 @@ bool FollowMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
Movement::MoveSplineInit init(owner);
init.MovebyPath(i_path->GetPath());
if (_inheritWalkState)
init.SetWalk(target->IsWalking() || target->movespline->isWalking());
init.SetWalk(target->IsWalking());
if (_inheritSpeed)
if (Optional<float> velocity = GetVelocity(owner, target, i_path->GetActualEndPosition(), owner->IsGuardian()))
@@ -116,7 +116,6 @@ namespace Movement
[[nodiscard]] bool Finalized() const { return splineflags.done; }
[[nodiscard]] bool isCyclic() const { return splineflags.cyclic; }
[[nodiscard]] bool isFalling() const { return splineflags.falling; }
[[nodiscard]] bool isWalking() const { return splineflags.walkmode; }
[[nodiscard]] bool isBoarding() const { return splineflags.transportEnter || splineflags.transportExit; }
[[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3(); }
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1) : Vector3(); }
@@ -40,7 +40,7 @@ namespace Movement
Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag
No_Spline = 0x00000400,
Parabolic = 0x00000800, // Affects elevation computation, can't be combined with Falling flag
Walkmode = 0x00001000,
CanSwim = 0x00001000,
Flying = 0x00002000, // Smooth movement(Catmullrom interpolation mode), flying animation
OrientationFixed = 0x00004000, // Model orientation fixed
Final_Point = 0x00008000,
@@ -117,7 +117,7 @@ namespace Movement
bool falling : 1;
bool no_spline : 1;
bool parabolic : 1;
bool walkmode : 1;
bool canSwim : 1;
bool flying : 1;
bool orientationFixed : 1;
bool final_point : 1;
@@ -118,7 +118,7 @@ namespace Movement
// If spline is initialized with SetWalk method it only means we need to select
// walk move speed for it but not add walk flag to unit
uint32 moveFlagsForSpeed = moveFlags;
if (args.flags.walkmode)
if (args.walk)
moveFlagsForSpeed |= MOVEMENTFLAG_WALKING;
else
moveFlagsForSpeed &= ~MOVEMENTFLAG_WALKING;
@@ -199,7 +199,7 @@ namespace Movement
args.splineId = splineIdGen.NewId();
args.TransformForTransport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID();
// mix existing state into new
args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
args.walk = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
args.flags.flying = unit->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY));
}
@@ -154,7 +154,7 @@ namespace Movement
};
inline void MoveSplineInit::SetFly() { args.flags.EnableFlying(); }
inline void MoveSplineInit::SetWalk(bool enable) { args.flags.walkmode = enable; }
inline void MoveSplineInit::SetWalk(bool enable) { args.walk = enable; }
inline void MoveSplineInit::SetSmooth() { args.flags.EnableCatmullRom(); }
inline void MoveSplineInit::SetCyclic() { args.flags.cyclic = true; }
inline void MoveSplineInit::SetFall() { args.flags.EnableFalling(); }
@@ -59,6 +59,7 @@ namespace Movement
float initialOrientation{0.f};
bool HasVelocity{false};
bool TransformForTransport{true};
bool walk;
/** Returns true to show that the arguments were configured correctly and MoveSpline initialization will succeed. */
bool Validate(Unit* unit) const;
@@ -153,7 +153,7 @@ namespace Movement
STR(Falling ), // 0x00000200, // Not Compartible With Trajectory Movement
STR(No_Spline ), // 0x00000400,
STR(Trajectory ), // 0x00000800, // Not Compartible With Fall Movement
STR(Walkmode ), // 0x00001000,
STR(CanSwim ), // 0x00001000,
STR(Flying ), // 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation
STR(Knockback ), // 0x00004000, // Model Orientation Fixed
STR(Final_Point ), // 0x00008000,
@@ -29,14 +29,14 @@ void ScriptMgr::OnNetworkStop()
CALL_ENABLED_HOOKS(ServerScript, SERVERHOOK_ON_NETWORK_STOP, script->OnNetworkStop());
}
void ScriptMgr::OnSocketOpen(std::shared_ptr<WorldSocket> socket)
void ScriptMgr::OnSocketOpen(std::shared_ptr<WorldSocket> const& socket)
{
ASSERT(socket);
CALL_ENABLED_HOOKS(ServerScript, SERVERHOOK_ON_SOCKET_OPEN, script->OnSocketOpen(socket));
}
void ScriptMgr::OnSocketClose(std::shared_ptr<WorldSocket> socket)
void ScriptMgr::OnSocketClose(std::shared_ptr<WorldSocket> const& socket)
{
ASSERT(socket);
@@ -46,11 +46,11 @@ public:
virtual void OnNetworkStop() { }
// Called when a remote socket establishes a connection to the server. Do not store the socket object.
virtual void OnSocketOpen(std::shared_ptr<WorldSocket> /*socket*/) { }
virtual void OnSocketOpen(std::shared_ptr<WorldSocket> const& /*socket*/) { }
// Called when a socket is closed. Do not store the socket object, and do not rely on the connection
// being open; it is not.
virtual void OnSocketClose(std::shared_ptr<WorldSocket> /*socket*/) { }
virtual void OnSocketClose(std::shared_ptr<WorldSocket> const& /*socket*/) { }
/**
* @brief This hook called when a packet is sent to a client. The packet object is a copy of the original packet, so reading and modifying it is safe.
+2 -2
View File
@@ -174,8 +174,8 @@ public: /* SpellScriptLoader */
public: /* ServerScript */
void OnNetworkStart();
void OnNetworkStop();
void OnSocketOpen(std::shared_ptr<WorldSocket> socket);
void OnSocketClose(std::shared_ptr<WorldSocket> socket);
void OnSocketOpen(std::shared_ptr<WorldSocket> const& socket);
void OnSocketClose(std::shared_ptr<WorldSocket> const& socket);
bool CanPacketReceive(WorldSession* session, WorldPacket const& packet);
void OnPacketReceived(WorldSession* session, WorldPacket const& packet);
bool CanPacketSend(WorldSession* session, WorldPacket const& packet);
+9 -9
View File
@@ -116,7 +116,7 @@ void EncryptableAndCompressiblePacket::CompressIfNeeded()
SetOpcode(SMSG_COMPRESSED_UPDATE_OBJECT);
}
WorldSocket::WorldSocket(tcp::socket&& socket)
WorldSocket::WorldSocket(IoContextTcpSocket&& socket)
: Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096), _loggingPackets(false)
{
Acore::Crypto::GetRandomBytes(_authSeed);
@@ -238,10 +238,10 @@ void WorldSocket::OnClose()
}
}
void WorldSocket::ReadHandler()
SocketReadCallbackResult WorldSocket::ReadHandler()
{
if (!IsOpen())
return;
return SocketReadCallbackResult::Stop;
MessageBuffer& packet = GetReadBuffer();
while (packet.GetActiveSize() > 0)
@@ -264,7 +264,7 @@ void WorldSocket::ReadHandler()
if (!ReadHeaderHandler())
{
CloseSocket();
return;
return SocketReadCallbackResult::Stop;
}
}
@@ -295,11 +295,11 @@ void WorldSocket::ReadHandler()
CloseSocket();
}
return;
return SocketReadCallbackResult::Stop;
}
}
AsyncRead();
return SocketReadCallbackResult::KeepReading;
}
bool WorldSocket::ReadHeaderHandler()
@@ -329,7 +329,7 @@ bool WorldSocket::ReadHeaderHandler()
return true;
}
struct AuthSession
struct ClientAuthSession
{
uint32 BattlegroupID = 0;
uint32 LoginServerType = 0;
@@ -528,7 +528,7 @@ void WorldSocket::SendPacket(WorldPacket const& packet)
void WorldSocket::HandleAuthSession(WorldPacket & recvPacket)
{
std::shared_ptr<AuthSession> authSession = std::make_shared<AuthSession>();
std::shared_ptr<ClientAuthSession> authSession = std::make_shared<ClientAuthSession>();
// Read the content of the packet
recvPacket >> authSession->Build;
@@ -552,7 +552,7 @@ void WorldSocket::HandleAuthSession(WorldPacket & recvPacket)
_queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1)));
}
void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSession, PreparedQueryResult result)
void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> authSession, PreparedQueryResult result)
{
// Stop if the account is not found
if (!result)
+6 -6
View File
@@ -65,21 +65,21 @@ struct ClientPktHeader
};
#pragma pack(pop)
struct AuthSession;
struct ClientAuthSession;
class AC_GAME_API WorldSocket : public Socket<WorldSocket>
class AC_GAME_API WorldSocket final : public Socket<WorldSocket>
{
typedef Socket<WorldSocket> BaseSocket;
public:
WorldSocket(tcp::socket&& socket);
WorldSocket(IoContextTcpSocket&& socket);
~WorldSocket();
WorldSocket(WorldSocket const& right) = delete;
WorldSocket& operator=(WorldSocket const& right) = delete;
void Start() override;
bool Update() override;
bool Update() final;
void SendPacket(WorldPacket const& packet);
@@ -90,7 +90,7 @@ public:
protected:
void OnClose() override;
void ReadHandler() override;
SocketReadCallbackResult ReadHandler() final;
bool ReadHeaderHandler();
enum class ReadDataHandlerResult
@@ -113,7 +113,7 @@ private:
void SendPacketAndLogOpcode(WorldPacket const& packet);
void HandleSendAuthSession();
void HandleAuthSession(WorldPacket& recvPacket);
void HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSession, PreparedQueryResult result);
void HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> authSession, PreparedQueryResult result);
void LoadSessionPermissionsCallback(PreparedQueryResult result);
void SendAuthResponseError(uint8 code);
+4 -4
View File
@@ -25,13 +25,13 @@
class WorldSocketThread : public NetworkThread<WorldSocket>
{
public:
void SocketAdded(std::shared_ptr<WorldSocket> sock) override
void SocketAdded(std::shared_ptr<WorldSocket> const& sock) override
{
sock->SetSendBufferSize(sWorldSocketMgr.GetApplicationSendBufferSize());
sScriptMgr->OnSocketOpen(sock);
}
void SocketRemoved(std::shared_ptr<WorldSocket> sock) override
void SocketRemoved(std::shared_ptr<WorldSocket> const& sock) override
{
sScriptMgr->OnSocketClose(sock);
}
@@ -81,7 +81,7 @@ void WorldSocketMgr::StopNetwork()
sScriptMgr->OnNetworkStop();
}
void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)
void WorldSocketMgr::OnSocketOpen(IoContextTcpSocket&& sock, uint32 threadIndex)
{
// set some options here
if (_socketSystemSendBufferSize >= 0)
@@ -109,7 +109,7 @@ void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)
}
}
BaseSocketMgr::OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex);
BaseSocketMgr::OnSocketOpen(std::move(sock), threadIndex);
}
NetworkThread<WorldSocket>* WorldSocketMgr::CreateThreads() const
+3 -3
View File
@@ -41,7 +41,7 @@ public:
/// Stops all network threads, It will wait for all running threads .
void StopNetwork() override;
void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) override;
void OnSocketOpen(IoContextTcpSocket&& sock, uint32 threadIndex) override;
std::size_t GetApplicationSendBufferSize() const { return _socketApplicationSendBufferSize; }
@@ -50,9 +50,9 @@ protected:
NetworkThread<WorldSocket>* CreateThreads() const override;
static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex)
static void OnSocketAccept(IoContextTcpSocket&& sock, uint32 threadIndex)
{
Instance().OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex);
Instance().OnSocketOpen(std::move(sock), threadIndex);
}
private:
@@ -24,6 +24,7 @@
#include "Chat.h"
#include "CommandScript.h"
#include "GroupMgr.h"
#include "Language.h"
#include "Player.h"
#include "SpellAuras.h"
@@ -211,6 +212,16 @@ public:
CharacterDatabase.Execute(stmt);
}
if (isInstance)
{
if (ObjectGuid groupId = sCharacterCache->GetCharacterGroupGuidByGuid(guid))
if (Group* group = sGroupMgr->GetGroupByGUID(groupId.GetCounter()))
if (group->isLFGGroup())
Player::RemoveFromGroup(group, guid);
}
else if (target && target->GetMap()->IsBattleground())
target->LeaveBattleground();
handler->PSendSysMessage("{} of {} Deserter has been added to player {}.", secsToTimeString(duration), isInstance ? "Instance" : "Battleground", handler->playerLink(*playerName));
return true;
}
@@ -215,7 +215,7 @@ struct boss_archimonde : public BossAI
scheduler.CancelAll();
me->SetReactState(REACT_PASSIVE);
DoCastAOE(SPELL_PROTECTION_OF_ELUNE, true);
Talk(SAY_ENRAGE);
Talk(SAY_DEATH);
_enraged = true;
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
@@ -172,7 +172,7 @@ struct boss_hadronox : public BossAI
SummonCrusherPack(SUMMON_GROUP_CRUSHER_3);
events.ScheduleEvent(EVENT_HADRONOX_MOVE1, 0s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE2, 45s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE3, 90s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE3, 70s);
}
}
@@ -1137,7 +1137,7 @@ public:
{
me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_SPECIAL);
Talk(SAY_LK_SUMMON_VALKYR);
DoCastSelf(IsHeroic() ? SPELL_SUMMON_VALKYR_PERIODIC : SPELL_SUMMON_VALKYR);
DoCastSelf(Is25ManRaid() ? SPELL_SUMMON_VALKYR_PERIODIC : SPELL_SUMMON_VALKYR);
events.ScheduleEvent(EVENT_SUMMON_VALKYR, 45s, EVENT_GROUP_ABILITIES);
// schedule a defile (or reschedule it) if next defile event
@@ -44,10 +44,7 @@ enum Spells
enum Misc
{
ACHIEV_TIMED_START_EVENT = 9891,
EVENT_SPAWN_CRYPT_GUARDS_1 = 0,
EVENT_BERSERK = 1,
EVENT_SPAWN_CRYPT_GUARDS_EXTRA = 2,
ACHIEV_TIMED_START_EVENT = 9891
};
Position const cryptguardPositions[] = {
@@ -121,9 +118,10 @@ struct boss_anubrekhan : public BossAI
SummonCryptGuards();
if (!Is25ManRaid())
{
ScheduleUniqueTimedEvent(17500ms, [&] {
me->m_Events.AddEventAtOffset([this]()
{
me->SummonCreature(NPC_CRYPT_GUARD, cryptguardPositions[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
}, EVENT_SPAWN_CRYPT_GUARDS_1);
}, 17500ms);
}
ScheduleTimedEvent(15s, [&] {
@@ -255,7 +255,8 @@ class spell_gluth_decimate : public SpellScript
Unit::DealDamage(GetCaster(), cTarget, damage);
return;
}
GetCaster()->CastCustomSpell(SPELL_DECIMATE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, unitTarget);
GetCaster()->CastSpell(unitTarget, SPELL_DECIMATE_DAMAGE);
}
}
@@ -265,8 +266,38 @@ class spell_gluth_decimate : public SpellScript
}
};
// 28375 - Decimate
class spell_gluth_decimate_damage : public SpellScript
{
PrepareSpellScript(spell_gluth_decimate_damage)
void RecalculateDamage()
{
Unit* target = GetHitUnit();
if (!target)
return;
int32 targetHealth = int32(target->GetHealth());
int32 fivePctHealth = int32(target->CountPctFromMaxHealth(5));
// Damage needed to leave the target at exactly 5%
int32 damage = targetHealth - fivePctHealth;
if (damage <= 0)
damage = 0;
SetHitDamage(damage);
}
void Register() override
{
OnHit += SpellHitFn(spell_gluth_decimate_damage::RecalculateDamage);
}
};
void AddSC_boss_gluth()
{
new boss_gluth();
RegisterSpellScript(spell_gluth_decimate);
RegisterSpellScript(spell_gluth_decimate_damage);
}
@@ -18,6 +18,7 @@
#include "CreatureScript.h"
#include "InstanceMapScript.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "nexus.h"
#include "Player.h"
#include "Group.h"
@@ -44,6 +45,8 @@ public:
{
instance_nexus_InstanceMapScript(Map* map) : InstanceScript(map) {}
GuidVector _frayerGUIDs;
void Initialize() override
{
SetHeaders(DataHeader);
@@ -80,6 +83,23 @@ public:
if (GetTeamIdInInstance() == TEAM_ALLIANCE)
creature->UpdateEntry(NPC_COMMANDER_KOLURG);
break;
case NPC_CRYSTALLINE_FRAYER:
_frayerGUIDs.push_back(creature->GetGUID());
break;
}
}
void KillAllFrayers()
{
for (ObjectGuid const& guid : _frayerGUIDs)
{
if (Creature* frayer = instance->GetCreature(guid))
{
frayer->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
frayer->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
frayer->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
Unit::Kill(frayer, frayer);
}
}
}
@@ -141,7 +161,13 @@ public:
if (!InstanceScript::SetBossState(id, state))
return false;
if (state != DONE || id > DATA_ORMOROK_EVENT)
if (state != DONE)
return true;
if (id == DATA_ORMOROK_EVENT)
KillAllFrayers();
if (id > DATA_ORMOROK_EVENT)
return true;
BossInfo const* bossInfo = GetBossInfo(id + DATA_TELESTRA_ORB);
@@ -156,9 +182,17 @@ enum eFrayer
{
SPELL_SUMMON_SEED_POD = 52796,
SPELL_SEED_POD = 48082,
SPELL_AURA_OF_REGENERATION = 52067,
SPELL_AURA_OF_REGENERATION = 57056,
SPELL_CRYSTAL_BLOOM = 48058,
SPELL_ENSNARE = 48053
SPELL_ENSNARE = 48053,
SAY_EMOTE = 0
};
enum FrayerGroups
{
GROUP_COMBAT = 1,
GROUP_SEED_POD = 2
};
struct npc_crystalline_frayer : public ScriptedAI
@@ -166,27 +200,44 @@ struct npc_crystalline_frayer : public ScriptedAI
npc_crystalline_frayer(Creature* creature) : ScriptedAI(creature) { }
bool _allowDeath;
uint32 restoreTimer;
uint32 abilityTimer1;
uint32 abilityTimer2;
bool _inSeedPod;
TaskScheduler _scheduler;
void Reset() override
{
restoreTimer = 0;
abilityTimer1 = 0;
abilityTimer2 = 30000;
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
_allowDeath = false;
_inSeedPod = false;
_scheduler.CancelAll();
me->RemoveAllAuras();
me->SetObjectScale(1.0f);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
me->SetRegeneratingHealth(true);
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveRandom(10.0f);
}
void JustEngagedWith(Unit*) override
{
_allowDeath = me->GetInstanceScript()->GetBossState(DATA_ORMOROK_EVENT) == DONE;
if (InstanceScript* instance = me->GetInstanceScript())
_allowDeath = instance->GetBossState(DATA_ORMOROK_EVENT) == DONE;
_scheduler.Schedule(5s, GROUP_COMBAT, [this](TaskContext context)
{
DoCastVictim(SPELL_ENSNARE);
context.Repeat(5s);
}).Schedule(0s, GROUP_COMBAT, [this](TaskContext context)
{
DoCastVictim(SPELL_CRYSTAL_BLOOM);
context.Repeat(30s);
});
}
void EnterEvadeMode(EvadeReason why) override
{
if (me->isRegeneratingHealth())
if (!_inSeedPod)
ScriptedAI::EnterEvadeMode(why);
}
@@ -196,57 +247,67 @@ struct npc_crystalline_frayer : public ScriptedAI
{
if (!_allowDeath)
{
me->RemoveAllAuras();
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(true);
damage = 0;
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetRegeneratingHealth(false);
me->CastSpell(me, SPELL_SUMMON_SEED_POD, true);
me->CastSpell(me, SPELL_SEED_POD, true);
me->CastSpell(me, SPELL_AURA_OF_REGENERATION, false);
restoreTimer = 1;
EnterSeedPod();
}
}
}
void EnterSeedPod()
{
_inSeedPod = true;
_scheduler.CancelGroup(GROUP_COMBAT);
me->AttackStop();
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(true);
me->RemoveAllAuras();
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
me->SetRegeneratingHealth(false);
me->SetObjectScale(0.6f);
DoCastSelf(SPELL_SEED_POD, true);
DoCastSelf(SPELL_SUMMON_SEED_POD, true);
DoCastSelf(SPELL_AURA_OF_REGENERATION, true);
_scheduler.Schedule(90s, GROUP_SEED_POD, [this](TaskContext /*context*/)
{
LeaveSeedPod();
});
}
void LeaveSeedPod()
{
_inSeedPod = false;
Talk(SAY_EMOTE);
me->RemoveAurasDueToSpell(SPELL_SEED_POD);
me->RemoveAurasDueToSpell(SPELL_AURA_OF_REGENERATION);
me->SetObjectScale(1.0f);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC);
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
me->SetRegeneratingHealth(true);
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveRandom(10.0f);
}
void UpdateAI(uint32 diff) override
{
if (restoreTimer)
{
restoreTimer += diff;
if (restoreTimer >= 90 * IN_MILLISECONDS)
{
Talk(0);
me->SetRegeneratingHealth(true);
restoreTimer = 0;
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
_scheduler.Update(diff);
if (_inSeedPod)
return;
}
if (!UpdateVictim())
return;
abilityTimer1 += diff;
abilityTimer2 += diff;
if (abilityTimer1 >= 5000)
{
me->CastSpell(me->GetVictim(), SPELL_ENSNARE, false);
abilityTimer1 = 0;
}
if (abilityTimer2 >= 30000)
{
me->CastSpell(me->GetVictim(), SPELL_CRYSTAL_BLOOM, false);
abilityTimer2 = 0;
}
}
};
@@ -50,6 +50,7 @@ enum Npcs
NPC_COMMANDER_STOUTBEARD = 26796,
NPC_COMMANDER_KOLURG = 26798,
NPC_CRYSTALLINE_FRAYER = 26793,
GO_TELESTRA_SPHERE = 188526,
GO_ANOMALUS_SPHERE = 188527,
@@ -276,6 +276,7 @@ public:
orb->RemoveAurasDueToSpell(SPELL_AWAKEN_SUBBOSS);
me->RemoveAurasDueToSpell(SPELL_FREEZE);
me->GetThreatMgr().ResetAllThreat();
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
me->SetControlled(false, UNIT_STATE_STUNNED);
// SETINCOMBATWITHZONE
@@ -610,150 +610,6 @@ private:
BetrayalState _state;
};
/*####
## npc_drakuru_shackles
####*/
enum DrakuruShackles
{
NPC_RAGECLAW = 29686,
QUEST_TROLLS_IS_GONE_CRAZY = 12861,
SPELL_LEFT_CHAIN = 59951,
SPELL_RIGHT_CHAIN = 59952,
SPELL_UNLOCK_SHACKLE = 55083,
SPELL_FREE_RAGECLAW = 55223
};
class npc_drakuru_shackles : public CreatureScript
{
public:
npc_drakuru_shackles() : CreatureScript("npc_drakuru_shackles") { }
struct npc_drakuru_shacklesAI : public NullCreatureAI
{
npc_drakuru_shacklesAI(Creature* creature) : NullCreatureAI(creature)
{
_rageclawGUID.Clear();
timer = 0;
}
void Reset() override
{
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void UpdateAI(uint32 diff) override
{
timer += diff;
if (timer >= 2000)
{
timer = 0;
if (_rageclawGUID)
return;
if (Creature* cr = me->FindNearestCreature(NPC_RAGECLAW, 10.0f))
{
_rageclawGUID = cr->GetGUID();
LockRageclaw(cr);
}
}
}
void LockRageclaw(Creature* rageclaw)
{
// pointer check not needed
me->SetFacingToObject(rageclaw);
rageclaw->SetFacingToObject(me);
DoCast(rageclaw, SPELL_LEFT_CHAIN, true);
DoCast(rageclaw, SPELL_RIGHT_CHAIN, true);
}
void UnlockRageclaw(Unit* /*who*/, Creature* rageclaw)
{
// pointer check not needed
DoCast(rageclaw, SPELL_FREE_RAGECLAW, true);
_rageclawGUID.Clear();
me->DespawnOrUnsummon(1ms);
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
if (spell->Id == SPELL_UNLOCK_SHACKLE)
{
if (caster->ToPlayer()->GetQuestStatus(QUEST_TROLLS_IS_GONE_CRAZY) == QUEST_STATUS_INCOMPLETE)
{
if (Creature* rageclaw = ObjectAccessor::GetCreature(*me, _rageclawGUID))
{
UnlockRageclaw(caster, rageclaw);
caster->ToPlayer()->KilledMonster(rageclaw->GetCreatureTemplate(), _rageclawGUID);
me->DespawnOrUnsummon();
}
else
me->setDeathState(DeathState::JustDied);
}
}
}
private:
ObjectGuid _rageclawGUID;
uint32 timer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_drakuru_shacklesAI(creature);
}
};
/*####
## npc_captured_rageclaw
####*/
enum Rageclaw
{
SPELL_UNSHACKLED = 55085,
SPELL_KNEEL = 39656,
SAY_RAGECLAW = 0
};
class npc_captured_rageclaw : public CreatureScript
{
public:
npc_captured_rageclaw() : CreatureScript("npc_captured_rageclaw") { }
struct npc_captured_rageclawAI : public NullCreatureAI
{
npc_captured_rageclawAI(Creature* creature) : NullCreatureAI(creature) { }
void Reset() override
{
me->SetFaction(FACTION_FRIENDLY);
DoCast(me, SPELL_KNEEL, true); // Little Hack for kneel - Thanks Illy :P
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id == SPELL_FREE_RAGECLAW)
{
me->RemoveAurasDueToSpell(SPELL_LEFT_CHAIN);
me->RemoveAurasDueToSpell(SPELL_RIGHT_CHAIN);
me->RemoveAurasDueToSpell(SPELL_KNEEL);
me->SetFaction(me->GetCreatureTemplate()->faction);
DoCast(me, SPELL_UNSHACKLED, true);
Talk(SAY_RAGECLAW);
me->GetMotionMaster()->MoveRandom(10);
me->DespawnOrUnsummon(10s);
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_captured_rageclawAI(creature);
}
};
/*####
## npc_released_offspring_harkoa
####*/
@@ -973,8 +829,6 @@ void AddSC_zuldrak()
new npc_finklestein();
new go_finklestein_cauldron();
RegisterCreatureAI(npc_overlord_drakuru_betrayal);
new npc_drakuru_shackles();
new npc_captured_rageclaw();
new npc_released_offspring_harkoa();
new npc_crusade_recruit();
new go_scourge_enclosure();
@@ -56,17 +56,20 @@ struct boss_talon_king_ikiss : public BossAI
void Reset() override
{
_Reset();
_spoken = false;
me->SetReactState(REACT_AGGRESSIVE);
ScheduleHealthCheckEvent({ 80, 50, 25 }, [&] {
me->InterruptNonMeleeSpells(false);
me->SetReactState(REACT_PASSIVE);
me->AttackStop();
DoCastAOE(SPELL_BLINK);
DoCastSelf(SPELL_ARCANE_BUBBLE, true);
Talk(EMOTE_ARCANE_EXP);
scheduler.Schedule(1s, [this](TaskContext /*context*/)
{
DoCastAOE(SPELL_ARCANE_EXPLOSION);
}).Schedule(6500ms, [this](TaskContext /*context*/)
}).Schedule(7s, [this](TaskContext /*context*/)
{
me->SetReactState(REACT_AGGRESSIVE);
me->GetThreatMgr().ResetAllThreat();
});
});
@@ -160,7 +163,7 @@ class spell_talon_king_ikiss_blink : public SpellScript
void HandleDummyHitTarget(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
GetHitUnit()->CastSpell(GetCaster(), SPELL_BLINK_TELEPORT, true);
GetCaster()->CastSpell(GetHitUnit(), SPELL_BLINK_TELEPORT, true);
}
void Register() override
@@ -90,7 +90,7 @@ struct boss_pathaleon_the_calculator : public BossAI
me->LoadEquipment(EQUIPMENT_FRENZY);
});
scheduler.Schedule(20s, 25s, [this](TaskContext context)
scheduler.Schedule(10s, 16s, [this](TaskContext context)
{
if (!_isEnraged)
{
@@ -113,7 +113,7 @@ struct boss_pathaleon_the_calculator : public BossAI
me->ModifyPower(POWER_MANA, 5000);
DoCastSelf(SPELL_ARCANE_TORRENT);
context.Repeat(15s);
}).Schedule(10s, 15s, [this](TaskContext context)
}).Schedule(10s, 16s, [this](TaskContext context)
{
if (DoCastRandomTarget(SPELL_DOMINATION, 0, 50.0f, true, false, false) == SPELL_CAST_OK)
{
+9 -8
View File
@@ -20,6 +20,7 @@
#include "IpAddress.h"
#include "Log.h"
#include "Socket.h"
#include "Systemd.h"
#include <atomic>
#include <boost/asio/ip/tcp.hpp>
@@ -32,7 +33,7 @@ constexpr auto ACORE_MAX_LISTEN_CONNECTIONS = boost::asio::socket_base::max_list
class AsyncAcceptor
{
public:
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
typedef void(*AcceptCallback)(IoContextTcpSocket&& newSocket, uint32 threadIndex);
AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port, bool supportSocketActivation = false) :
_acceptor(ioContext), _endpoint(Acore::Net::make_address(bindIp), port),
@@ -56,7 +57,7 @@ public:
template<AcceptCallback acceptCallback>
void AsyncAcceptWithCallback()
{
tcp::socket* socket;
IoContextTcpSocket* socket;
uint32 threadIndex;
std::tie(socket, threadIndex) = _socketFactory();
_acceptor.async_accept(*socket, [this, socket, threadIndex](boost::system::error_code error)
@@ -129,16 +130,16 @@ public:
_acceptor.close(err);
}
void SetSocketFactory(std::function<std::pair<tcp::socket*, uint32>()> func) { _socketFactory = func; }
void SetSocketFactory(std::function<std::pair<IoContextTcpSocket*, uint32>()> func) { _socketFactory = std::move(func); }
private:
std::pair<tcp::socket*, uint32> DefaultSocketFactory() { return std::make_pair(&_socket, 0); }
std::pair<IoContextTcpSocket*, uint32> DefaultSocketFactory() { return std::make_pair(&_socket, 0); }
tcp::acceptor _acceptor;
tcp::endpoint _endpoint;
tcp::socket _socket;
boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, IoContextTcpSocket::executor_type> _acceptor;
boost::asio::ip::tcp::endpoint _endpoint;
IoContextTcpSocket _socket;
std::atomic<bool> _closed;
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
std::function<std::pair<IoContextTcpSocket*, uint32>()> _socketFactory;
bool _supportSocketActivation;
};
+4 -4
View File
@@ -91,13 +91,13 @@ public:
SocketAdded(sock);
}
tcp::socket* GetSocketForAccept() { return &_acceptSocket; }
IoContextTcpSocket* GetSocketForAccept() { return &_acceptSocket; }
void EnableProxyProtocol() { _proxyHeaderReadingEnabled = true; }
protected:
virtual void SocketAdded(std::shared_ptr<SocketType> /*sock*/) { }
virtual void SocketRemoved(std::shared_ptr<SocketType> /*sock*/) { }
virtual void SocketAdded(std::shared_ptr<SocketType> const& /*sock*/) { }
virtual void SocketRemoved(std::shared_ptr<SocketType> const& /*sock*/) { }
void AddNewSockets()
{
@@ -229,7 +229,7 @@ private:
SocketContainer _newSockets;
Acore::Asio::IoContext _ioContext;
tcp::socket _acceptSocket;
IoContextTcpSocket _acceptSocket;
boost::asio::steady_timer _updateTimer;
bool _proxyHeaderReadingEnabled;
+48 -21
View File
@@ -21,9 +21,8 @@
#include "Log.h"
#include "MessageBuffer.h"
#include <atomic>
#include <boost/asio.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <functional>
#include <memory>
#include <queue>
#include <type_traits>
@@ -35,6 +34,23 @@ using boost::asio::ip::tcp;
#define AC_SOCKET_USE_IOCP
#endif
// Specialize boost socket for io_context executor instead of type-erased any_io_executor
// This avoids the type-erasure overhead of any_io_executor
using IoContextTcpSocket = boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::io_context::executor_type>;
enum class SocketReadCallbackResult
{
KeepReading,
Stop
};
enum class SocketState : uint8
{
Open = 0,
Closing = 1,
Closed = 2
};
enum ProxyHeaderReadingState {
PROXY_HEADER_READING_STATE_NOT_STARTED,
PROXY_HEADER_READING_STATE_STARTED,
@@ -51,8 +67,8 @@ template<class T>
class Socket : public std::enable_shared_from_this<T>
{
public:
explicit Socket(tcp::socket&& socket) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
_remotePort(_socket.remote_endpoint().port()), _readBuffer(), _closed(false), _closing(false), _isWritingAsync(false),
explicit Socket(IoContextTcpSocket&& socket) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()),
_remotePort(_socket.remote_endpoint().port()), _readBuffer(), _state(SocketState::Open), _isWritingAsync(false),
_proxyHeaderReadingState(PROXY_HEADER_READING_STATE_NOT_STARTED)
{
_readBuffer.Resize(READ_BLOCK_SIZE);
@@ -60,7 +76,7 @@ public:
virtual ~Socket()
{
_closed = true;
_state = SocketState::Closed;
boost::system::error_code error;
_socket.close(error);
}
@@ -69,13 +85,14 @@ public:
virtual bool Update()
{
if (_closed)
SocketState state = _state.load();
if (state == SocketState::Closed)
{
return false;
}
#ifndef AC_SOCKET_USE_IOCP
if (_isWritingAsync || (_writeQueue.empty() && !_closing))
if (_isWritingAsync || (_writeQueue.empty() && state != SocketState::Closing))
{
return true;
}
@@ -150,12 +167,18 @@ public:
[[nodiscard]] ProxyHeaderReadingState GetProxyHeaderReadingState() const { return _proxyHeaderReadingState; }
[[nodiscard]] bool IsOpen() const { return !_closed && !_closing; }
[[nodiscard]] bool IsOpen() const { return _state.load() == SocketState::Open; }
void CloseSocket()
{
if (_closed.exchange(true))
return;
SocketState expected = SocketState::Open;
if (!_state.compare_exchange_strong(expected, SocketState::Closed))
{
// If it was Closing, try to transition to Closed
expected = SocketState::Closing;
if (!_state.compare_exchange_strong(expected, SocketState::Closed))
return; // Already closed
}
boost::system::error_code shutdownError;
_socket.shutdown(boost::asio::socket_base::shutdown_send, shutdownError);
@@ -168,13 +191,17 @@ public:
}
/// Marks the socket for closing after write buffer becomes empty
void DelayedCloseSocket() { _closing = true; }
void DelayedCloseSocket()
{
SocketState expected = SocketState::Open;
_state.compare_exchange_strong(expected, SocketState::Closing);
}
MessageBuffer& GetReadBuffer() { return _readBuffer; }
protected:
virtual void OnClose() { }
virtual void ReadHandler() = 0;
virtual SocketReadCallbackResult ReadHandler() = 0;
bool AsyncProcessQueue()
{
@@ -188,7 +215,7 @@ protected:
_socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler,
this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
#else
_socket.async_wait(tcp::socket::wait_write, [self = this->shared_from_this()](boost::system::error_code error)
_socket.async_wait(boost::asio::socket_base::wait_write, [self = this->shared_from_this()](boost::system::error_code error)
{
self->WriteHandlerWrapper(error, 0);
});
@@ -216,7 +243,8 @@ private:
}
_readBuffer.WriteCompleted(transferredBytes);
ReadHandler();
if (ReadHandler() == SocketReadCallbackResult::KeepReading)
AsyncRead();
}
// ProxyReadHeaderHandler reads Proxy Protocol v2 header (v1 is not supported).
@@ -344,7 +372,7 @@ private:
if (!_writeQueue.empty())
AsyncProcessQueue();
else if (_closing)
else if (_state.load() == SocketState::Closing)
CloseSocket();
}
else
@@ -380,7 +408,7 @@ private:
_writeQueue.pop();
if (_closing && _writeQueue.empty())
if (_state.load() == SocketState::Closing && _writeQueue.empty())
{
CloseSocket();
}
@@ -391,7 +419,7 @@ private:
{
_writeQueue.pop();
if (_closing && _writeQueue.empty())
if (_state.load() == SocketState::Closing && _writeQueue.empty())
{
CloseSocket();
}
@@ -406,7 +434,7 @@ private:
_writeQueue.pop();
if (_closing && _writeQueue.empty())
if (_state.load() == SocketState::Closing && _writeQueue.empty())
{
CloseSocket();
}
@@ -415,7 +443,7 @@ private:
}
#endif
tcp::socket _socket;
IoContextTcpSocket _socket;
boost::asio::ip::address _remoteAddress;
uint16 _remotePort;
@@ -423,8 +451,7 @@ private:
MessageBuffer _readBuffer;
std::queue<MessageBuffer> _writeQueue;
std::atomic<bool> _closed;
std::atomic<bool> _closing;
std::atomic<SocketState> _state;
bool _isWritingAsync;
+2 -2
View File
@@ -91,7 +91,7 @@ public:
_threads[i].Wait();
}
virtual void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex)
virtual void OnSocketOpen(IoContextTcpSocket&& sock, uint32 threadIndex)
{
try
{
@@ -117,7 +117,7 @@ public:
return min;
}
std::pair<tcp::socket*, uint32> GetSocketForAccept()
std::pair<IoContextTcpSocket*, uint32> GetSocketForAccept()
{
uint32 threadIndex = SelectThreadWithMinConnections();
return { _threads[threadIndex].GetSocketForAccept(), threadIndex };