Merge branch 'master' into Playerbot

This commit is contained in:
郑佩茹
2023-02-17 11:37:31 -07:00
417 changed files with 3381 additions and 903 deletions

View File

@@ -68,7 +68,12 @@ void CombatAI::JustDied(Unit* killer)
me->CastSpell(killer, *i, true);
}
void CombatAI::EnterCombat(Unit* who)
/**
* @brief Called for reaction when initially engaged
*
* @param who Who 'me' Engaged combat with
*/
void CombatAI::JustEngagedWith(Unit* who)
{
for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
{
@@ -114,7 +119,12 @@ void CasterAI::InitializeAI()
m_attackDist = MELEE_RANGE;
}
void CasterAI::EnterCombat(Unit* who)
/**
* @brief Called for reaction when initially engaged
*
* @param who Who 'me' Engaged combat with
*/
void CasterAI::JustEngagedWith(Unit* who)
{
if (spells.empty())
return;

View File

@@ -43,7 +43,7 @@ public:
void InitializeAI() override;
void Reset() override;
void EnterCombat(Unit* who) override;
void JustEngagedWith(Unit* who) override;
void JustDied(Unit* killer) override;
void UpdateAI(uint32 diff) override;
@@ -61,7 +61,7 @@ public:
void InitializeAI() override;
void AttackStart(Unit* victim) override { AttackStartCaster(victim, m_attackDist); }
void UpdateAI(uint32 diff) override;
void EnterCombat(Unit* /*who*/) override;
void JustEngagedWith(Unit* /*who*/) override;
private:
float m_attackDist;
};

View File

@@ -69,7 +69,7 @@ void PossessedAI::KilledUnit(Unit* /*victim*/)
// victim->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
}
void CritterAI::EnterCombat(Unit* who)
void CritterAI::JustEngagedWith(Unit* who)
{
if (!me->HasUnitState(UNIT_STATE_FLEEING))
{

View File

@@ -68,7 +68,7 @@ class CritterAI : public PassiveAI
public:
explicit CritterAI(Creature* c) : PassiveAI(c) { }
void EnterCombat(Unit* /*who*/) override;
void JustEngagedWith(Unit* /*who*/) override;
void EnterEvadeMode(EvadeReason why) override;
void MovementInform(uint32 type, uint32 id) override;
void UpdateAI(uint32 /*diff*/) override { }

View File

@@ -332,6 +332,21 @@ public:
targetList.resize(num);
}
/**
* @brief Called when the unit enters combat
* (NOTE: Creature engage logic should NOT be here, but in JustEngagedWith, which happens once threat is established!)
*
* @todo Never invoked right now. Preparation for Combat Threat refactor
*/
virtual void JustEnteredCombat(Unit* /*who*/) { }
/**
* @brief Called when the unit leaves combat
*
* @todo Never invoked right now. Preparation for Combat Threat refactor
*/
virtual void JustExitedCombat() { }
// Called at any Damage to any victim (before damage apply)
virtual void DamageDealt(Unit* /*victim*/, uint32& /*damage*/, DamageEffectType /*damageType*/) { }

View File

@@ -116,8 +116,10 @@ public:
// Called for reaction at stopping attack at no attackers or targets
virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
// Called for reaction when initially engaged
virtual void EnterCombat(Unit* /*victim*/) {}
/**
* @brief Called for reaction when initially engaged
*/
virtual void JustEngagedWith(Unit* /*who*/) {}
// Called when the creature is killed
virtual void JustDied(Unit* /*killer*/) {}

View File

@@ -593,7 +593,7 @@ void BossAI::_JustDied()
}
}
void BossAI::_EnterCombat()
void BossAI::_JustEngagedWith()
{
me->SetCombatPulseDelay(5);
me->setActive(true);
@@ -690,7 +690,7 @@ void WorldBossAI::_JustDied()
summons.DespawnAll();
}
void WorldBossAI::_EnterCombat()
void WorldBossAI::_JustEngagedWith()
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true);
if (target)

View File

@@ -278,9 +278,9 @@ struct ScriptedAI : public CreatureAI
void Reset() override {}
//Called at creature aggro either by MoveInLOS or Attack Start
void EnterCombat(Unit* /*victim*/) override {}
void JustEngagedWith(Unit* /*who*/) override {}
// Called before EnterCombat even before the creature is in combat.
// Called before JustEngagedWith even before the creature is in combat.
void AttackStart(Unit* /*target*/) override;
// *************
@@ -455,13 +455,13 @@ public:
virtual void ScheduleTasks() { }
void Reset() override { _Reset(); }
void EnterCombat(Unit* /*who*/) override { _EnterCombat(); }
void JustEngagedWith(Unit* /*who*/) override { _JustEngagedWith(); }
void JustDied(Unit* /*killer*/) override { _JustDied(); }
void JustReachedHome() override { _JustReachedHome(); }
protected:
void _Reset();
void _EnterCombat();
void _JustEngagedWith();
void _JustDied();
void _JustReachedHome() { me->setActive(false); }
@@ -493,12 +493,12 @@ public:
virtual void ExecuteEvent(uint32 /*eventId*/) { }
void Reset() override { _Reset(); }
void EnterCombat(Unit* /*who*/) override { _EnterCombat(); }
void JustEngagedWith(Unit* /*who*/) override { _JustEngagedWith(); }
void JustDied(Unit* /*killer*/) override { _JustDied(); }
protected:
void _Reset();
void _EnterCombat();
void _JustEngagedWith();
void _JustDied();
EventMap events;

View File

@@ -787,7 +787,7 @@ void SmartAI::JustReachedHome()
mJustReset = false;
}
void SmartAI::EnterCombat(Unit* enemy)
void SmartAI::JustEngagedWith(Unit* enemy)
{
// Xinef: Interrupt channeled spells
if (IsAIControlled())

View File

@@ -80,7 +80,7 @@ public:
void JustReachedHome() override;
// Called for reaction at enter to combat if not in combat yet (enemy can be nullptr)
void EnterCombat(Unit* enemy) override;
void JustEngagedWith(Unit* enemy) override;
// Called for reaction at stopping attack at no attackers or targets
void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER) override;

View File

@@ -13692,7 +13692,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy, uint32 duration)
if (enemy)
{
if (IsAIEnabled)
creature->AI()->EnterCombat(enemy);
creature->AI()->JustEngagedWith(enemy);
if (creature->GetFormation())
creature->GetFormation()->MemberEngagingTarget(creature, enemy);

View File

@@ -481,6 +481,10 @@ void WorldSession::HandlePlayerLogoutOpcode(WorldPackets::Character::PlayerLogou
void WorldSession::HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCancel& /*logoutCancel*/)
{
// Player have already logged out serverside, too late to cancel
if (!GetPlayer())
return;
SetLogoutStartTime(0);
SendPacket(WorldPackets::Character::LogoutCancelAck().Write());

View File

@@ -527,7 +527,7 @@ void WorldSession::HandleBeginTradeOpcode(WorldPacket& /*recvPacket*/)
void WorldSession::SendCancelTrade()
{
if (PlayerLogout())
if (PlayerRecentlyLoggedOut() || PlayerLogout())
return;
SendTradeStatus(TRADE_STATUS_TRADE_CANCELED);
@@ -535,7 +535,9 @@ void WorldSession::SendCancelTrade()
void WorldSession::HandleCancelTradeOpcode(WorldPacket& /*recvPacket*/)
{
_player->TradeCancel(true);
// sended also after LOGOUT COMPLETE
if (_player) // needed because STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT
_player->TradeCancel(true);
}
void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)

View File

@@ -206,7 +206,7 @@ void OpcodeTable::Initialize()
/*0x04B*/ DEFINE_HANDLER(CMSG_LOGOUT_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutRequestOpcode );
/*0x04C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_RESPONSE, STATUS_NEVER);
/*0x04D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_COMPLETE, STATUS_NEVER);
/*0x04E*/ DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode );
/*0x04E*/ DEFINE_HANDLER(CMSG_LOGOUT_CANCEL, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleLogoutCancelOpcode);
/*0x04F*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGOUT_CANCEL_ACK, STATUS_NEVER);
/*0x050*/ DEFINE_HANDLER(CMSG_NAME_QUERY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleNameQueryOpcode );
/*0x051*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_NAME_QUERY_RESPONSE, STATUS_NEVER);
@@ -412,7 +412,7 @@ void OpcodeTable::Initialize()
/*0x119*/ DEFINE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleIgnoreTradeOpcode );
/*0x11A*/ DEFINE_HANDLER(CMSG_ACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptTradeOpcode );
/*0x11B*/ DEFINE_HANDLER(CMSG_UNACCEPT_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnacceptTradeOpcode );
/*0x11C*/ DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTradeOpcode );
/*0x11C*/ DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTradeOpcode);
/*0x11D*/ DEFINE_HANDLER(CMSG_SET_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeItemOpcode );
/*0x11E*/ DEFINE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleClearTradeItemOpcode );
/*0x11F*/ DEFINE_HANDLER(CMSG_SET_TRADE_GOLD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetTradeGoldOpcode );

View File

@@ -1353,9 +1353,10 @@ typedef Opcodes OpcodeServer;
/// Player state
enum SessionStatus
{
STATUS_AUTHED = 0, // Player authenticated (_player == nullptr, m_GUID has garbage)
STATUS_AUTHED = 0, // Player authenticated (_player == nullptr, m_playerRecentlyLogout = false or will be reset before handler call, m_GUID have garbage)
STATUS_LOGGEDIN, // Player in game (_player != nullptr, m_GUID == _player->GetGUID(), inWorld())
STATUS_TRANSFER, // Player transferring to another map (_player != nullptr, m_GUID == _player->GetGUID(), !inWorld())
STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, // _player != nullptr or _player == nullptr && m_playerRecentlyLogout && m_playerLogout, m_GUID store last _player guid)
STATUS_NEVER, // Opcode not accepted from client (deprecated or server side only)
STATUS_UNHANDLED, // Opcode not handled yet
};

View File

@@ -121,6 +121,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS
m_inQueue(false),
m_playerLoading(false),
m_playerLogout(false),
m_playerRecentlyLogout(false),
m_playerSave(false),
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
m_sessionDbLocaleIndex(locale),
@@ -333,28 +334,48 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
case STATUS_LOGGEDIN:
if (!_player)
{
// pussywizard: such packets were sent to do something for a character that has already logged out, skip them
}
else if (!_player->IsInWorld())
{
// pussywizard: such packets may do something important and the player is just being teleported, move to the end of the queue
// pussywizard: previously such were skipped, so leave it as it is xD proper code below if we wish to change that
// pussywizard: requeue only important packets not related to maps (PROCESS_THREADUNSAFE)
/*if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
//! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
//! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
if (!m_playerRecentlyLogout)
{
if (!firstDelayedPacket)
firstDelayedPacket = packet;
requeuePackets.push_back(packet);
deletePacket = false;
QueuePacket(packet);
}*/
}
else if (_player->IsInWorld() && AntiDOS.EvaluateOpcode(*packet, currentTime))
{
if (!sScriptMgr->CanPacketReceive(this, *packet))
{
break;
LOG_DEBUG("network", "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
"Player {} is currently not in world yet.", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet->GetOpcode())), GetPlayerInfo());
}
}
else if (_player->IsInWorld())
{
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
{
if (!sScriptMgr->CanPacketReceive(this, *packet))
{
break;
}
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
}
else
processedPackets = MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE; // break out of packet processing loop
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break;
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
if (!_player && !m_playerRecentlyLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
{
LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
"the player has not logged in yet and not recently logout");
}
else if (AntiDOS.EvaluateOpcode(*packet, currentTime))
{
// not expected _player or must checked in packet hanlder
if (!sScriptMgr->CanPacketReceive(this, *packet))
break;
opHandle->Call(this, *packet);
LogUnprocessedTail(packet);
@@ -384,6 +405,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater)
if (m_inQueue) // prevent cheating
break;
// some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
// however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
if (packet->GetOpcode() == CMSG_CHAR_ENUM)
m_playerRecentlyLogout = false;
if (AntiDOS.EvaluateOpcode(*packet, currentTime))
{
if (!sScriptMgr->CanPacketReceive(this, *packet))
@@ -735,6 +761,7 @@ void WorldSession::LogoutPlayer(bool save)
m_playerLogout = false;
m_playerSave = false;
m_playerRecentlyLogout = true;
SetLogoutStartTime(0);
}
@@ -1282,6 +1309,8 @@ void WorldSession::SendAddonsInfo()
void WorldSession::SetPlayer(Player* player)
{
_player = player;
// set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset
if (_player)
m_GUIDLow = _player->GetGUID().GetCounter();
}

View File

@@ -354,6 +354,7 @@ public:
bool PlayerLoading() const { return m_playerLoading; }
bool PlayerLogout() const { return m_playerLogout; }
bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; }
bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; }
void ReadAddonsInfo(ByteBuffer& data);
@@ -1169,7 +1170,7 @@ private:
// characters who failed on Player::BuildEnumData shouldn't login
GuidSet _legitCharacters;
ObjectGuid::LowType m_GUIDLow;
ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
Player* _player;
std::shared_ptr<WorldSocket> m_Socket;
std::string m_Address;
@@ -1190,6 +1191,7 @@ private:
bool m_inQueue; // session wait in auth.queue
bool m_playerLoading; // code processed in LoginPlayer
bool m_playerLogout; // code processed in LogoutPlayer
bool m_playerRecentlyLogout;
bool m_playerSave;
LocaleConstant m_sessionDbcLocale;
LocaleConstant m_sessionDbLocaleIndex;