This commit is contained in:
luis
2026-03-28 15:59:00 -03:00
parent 9618189a9f
commit de4bb784d6
7 changed files with 72 additions and 7 deletions
@@ -50,7 +50,7 @@ namespace Playerbot
{
PlayerbotCommandScript::PlayerbotCommandScript() : CommandScript("PlayerbotCommandScript") { }
ChatCommandTable PlayerbotCommandScript::GetCommands() const
std::span<ChatCommandBuilder const> PlayerbotCommandScript::GetCommands() const
{
static ChatCommandTable botFormationCommandTable =
{
@@ -1210,7 +1210,7 @@ namespace Playerbot
oss << "4. line - Horizontal line for maximum width coverage\n";
oss << "5. column - Vertical single-file march formation\n";
oss << "6. scatter - Spread formation for anti-AoE tactics\n";
oss << "7. circle - 360° perimeter coverage formation\n";
oss << "7. circle - 360� perimeter coverage formation\n";
oss << "8. dungeon - Optimized dungeon formation (tank/healer/dps roles)\n";
oss << "9. raid - Raid formation with 5-person groups\n";
oss << "\n";
@@ -25,6 +25,7 @@
#include "RBAC.h"
#include "ScriptMgr.h"
#include <optional>
#include <span>
#include <string_view>
namespace Playerbot
@@ -65,7 +66,7 @@ namespace Playerbot
public:
PlayerbotCommandScript();
Trinity::ChatCommands::ChatCommandTable GetCommands() const;
std::span<Trinity::ChatCommands::ChatCommandBuilder const> GetCommands() const;
private:
// Bot spawning commands
@@ -31,6 +31,10 @@ void TransmogManager::CollectAppearancesFromEquipment()
if (!_bot)
return;
// Guard against invalid bot state
if (!_bot->IsInWorld() || !_bot->GetSession())
return;
// Obtain session once and guard against NULL session
auto sess = _bot->GetSession();
if (!sess)
@@ -100,6 +104,10 @@ bool TransmogManager::ApplyOutfit(std::string const& outfitName)
if (!_bot)
return false;
// Guard against invalid bot state
if (!_bot->IsInWorld() || !_bot->GetSession())
return false;
auto it = _savedOutfits.find(outfitName);
if (it == _savedOutfits.end())
return false;
@@ -143,8 +151,12 @@ bool TransmogManager::ApplyOutfit(std::string const& outfitName)
if (applied > 0)
{
// Force visual update for nearby players
_bot->SetVisibleItemSlot(0, nullptr); // Trigger update
// Force visual update - iterate through all equipment slots properly
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_TABARD; ++slot)
{
Item* item = _bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
_bot->SetVisibleItemSlot(slot, item);
}
TC_LOG_DEBUG("module.playerbot", "TransmogManager: Bot {} applied outfit '{}' ({} slots)",
_bot->GetName(), outfitName, applied);
}
@@ -171,6 +183,10 @@ void TransmogManager::ClearTransmog()
if (!_bot)
return;
// Guard against invalid bot state
if (!_bot->IsInWorld() || !_bot->GetSession())
return;
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
{
Item* item = _bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
@@ -181,6 +197,13 @@ void TransmogManager::ClearTransmog()
item->SetState(ITEM_CHANGED, _bot);
}
// Update visual slots
for (uint8 slot = 0; slot < EQUIPMENT_SLOT_TABARD; ++slot)
{
Item* item = _bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
_bot->SetVisibleItemSlot(slot, item);
}
TC_LOG_DEBUG("module.playerbot", "TransmogManager: Bot {} cleared all transmog",
_bot->GetName());
}
@@ -202,6 +225,10 @@ bool TransmogManager::ShouldVisitTransmogrifier() const
if (!_bot)
return false;
// Guard against invalid bot state
if (!_bot->IsInWorld())
return false;
uint32 currentTime = GameTime::GetGameTimeMS();
if (currentTime - _lastTransmogVisitMs < TRANSMOG_VISIT_COOLDOWN_MS)
return false;
@@ -257,6 +284,10 @@ void TransmogManager::Update(uint32 /*diff*/)
if (!_bot)
return;
// Guard against invalid bot state
if (!_bot->IsInWorld())
return;
uint32 currentTime = GameTime::GetGameTimeMS();
if (currentTime - _lastUpdateMs < UPDATE_INTERVAL_MS)
return;
@@ -326,7 +357,7 @@ uint32 TransmogManager::GetItemAppearanceId(Item const* item)
TransmogManager* TransmogCoordinator::GetManager(Player* bot)
{
if (!bot)
if (!bot || !bot->IsInWorld())
return nullptr;
ObjectGuid guid = bot->GetGUID();
@@ -1273,6 +1273,12 @@ bool Player::TeleportTo(TeleportLocation const& teleportLocation, TeleportToOpti
return false;
}
if (IsBeingTeleportedFar())
{
TC_LOG_WARN("entities.player.teleport", "Player::TeleportTo: Player '{}' ({}) has stuck teleport state, resetting", GetGUID().ToString(), GetName());
ResetTeleportState();
}
// preparing unsummon pet if lost (we must get pet before teleportation or will not find it later)
Pet* pet = GetPet();
@@ -1518,6 +1524,16 @@ bool Player::TeleportToBGEntryPoint()
return TeleportTo(m_bgData.joinPos);
}
void Player::ResetTeleportState()
{
SetSemaphoreTeleportFar(false);
SetSemaphoreTeleportNear(false);
SetDelayedTeleportFlag(false);
RemoveUnitFlag(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_ON_TAXI);
GetMotionMaster()->Remove(FLIGHT_MOTION_TYPE);
TC_LOG_DEBUG("entities.player.teleport", "Player::ResetTeleportState: Reset teleport state for player {}", GetName());
}
void Player::ProcessDelayedOperations()
{
if (m_DelayedOperations == 0)
+1
View File
@@ -1236,6 +1236,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
bool TeleportTo(WorldLocation const& loc, TeleportToOptions options = TELE_TO_NONE, Optional<uint32> instanceId = {}, uint32 teleportSpellId = 0);
bool TeleportTo(TeleportLocation const& teleportLocation, TeleportToOptions options = TELE_TO_NONE, uint32 teleportSpellId = 0);
bool TeleportToBGEntryPoint();
void ResetTeleportState();
bool HasSummonPending() const;
void SendSummonRequestFrom(Unit* summoner);
@@ -170,6 +170,8 @@ void WorldSession::HandleMoveWorldportAck()
garrison->SendRemoteInfo();
}
player->UpdateZoneAndAreaId();
// flight fast teleport case
if (player->IsInFlight())
{
+15 -1
View File
@@ -1018,9 +1018,23 @@ void Spell::EffectTeleportUnits()
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
if (!unitTarget || unitTarget->IsInFlight())
if (!unitTarget)
return;
if (unitTarget->IsInFlight())
{
if (Player* player = unitTarget->ToPlayer())
{
TC_LOG_WARN("spells", "Spell::EffectTeleportUnits - Player {} is stuck in flight state, resetting", player->GetName());
player->GetMotionMaster()->Remove(FLIGHT_MOTION_TYPE);
player->RemoveUnitFlag(UNIT_FLAG_REMOVE_CLIENT_CONTROL | UNIT_FLAG_ON_TAXI);
}
else
{
return;
}
}
// If not exist data for dest location - return
if (!m_targets.HasDst())
{