mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-14 01:19:08 +00:00
Add thread safety for group operations (#1816)
Fixes crashes and race conditions when bots perform group/guild/arena operations by moving thread-unsafe code to world thread. Potentially fixes #1124 ## Changes - Added operation queue system that runs in world thread - Group operations (invite, remove, convert to raid, set leader) now queued - Arena formation refactored to use queue - Guild operations changed to use packet queueing ## Testing Set `MapUpdate.Threads` > 1 in worldserver.conf to enable multiple map threads, then test: - Group formation and disbanding - Arena team formation - Guild operations (invite, promote, demote, remove) - Run with TSAN cmake ../ \ -DCMAKE_CXX_FLAGS="-fsanitize=thread -g -O1" \ -DCMAKE_C_FLAGS="-fsanitize=thread -g -O1" \ -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread" \ -DCMAKE_INSTALL_PREFIX=/path/to/install \ -DCMAKE_BUILD_TYPE=RelWithDebInfo build export TSAN_OPTIONS="log_path=tsan_report:halt_on_error=0:second_deadlock_stack=1" ./worldserver The crashes/race conditions should no longer occur with concurrent map threads. ## New Files - `PlayerbotOperation.h` - Base class defining the operation interface (Execute, IsValid, GetPriority) - `PlayerbotOperations.h` - Concrete implementations: GroupInviteOperation, GroupRemoveMemberOperation, GroupConvertToRaidOperation, GroupSetLeaderOperation, ArenaGroupFormationOperation - `PlayerbotWorldThreadProcessor.h/cpp` - Singleton processor with mutex-protected queue, processes operations in WorldScript::OnUpdate hook, handles batch processing and validation --------- Co-authored-by: blinkysc <blinkysc@users.noreply.github.com> Co-authored-by: SaW <swerkhoven@outlook.com> Co-authored-by: bash <hermensb@gmail.com>
This commit is contained in:
@@ -58,6 +58,14 @@ Player* GuidManageAction::GetPlayer(Event event)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GuidManageAction::SendPacket(WorldPacket const& packet)
|
||||
{
|
||||
// make a heap copy because QueuePacket takes ownership
|
||||
WorldPacket* data = new WorldPacket(packet);
|
||||
|
||||
bot->GetSession()->QueuePacket(data);
|
||||
}
|
||||
|
||||
bool GuidManageAction::Execute(Event event)
|
||||
{
|
||||
Player* player = GetPlayer(event);
|
||||
@@ -84,12 +92,6 @@ bool GuildInviteAction::isUseful()
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_INVITE);
|
||||
}
|
||||
|
||||
void GuildInviteAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildInviteByName data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildInviteOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildInviteAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return !member->GetGuildId() && (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) ||
|
||||
@@ -101,12 +103,6 @@ bool GuildPromoteAction::isUseful()
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_PROMOTE);
|
||||
}
|
||||
|
||||
void GuildPromoteAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildPromoteMember data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildPromoteOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildPromoteAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member) - 1;
|
||||
@@ -117,12 +113,6 @@ bool GuildDemoteAction::isUseful()
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_DEMOTE);
|
||||
}
|
||||
|
||||
void GuildDemoteAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildDemoteMember data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildDemoteOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildDemoteAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member);
|
||||
@@ -133,12 +123,6 @@ bool GuildRemoveAction::isUseful()
|
||||
return bot->GetGuildId() && sGuildMgr->GetGuildById(bot->GetGuildId())->HasRankRight(bot, GR_RIGHT_REMOVE);
|
||||
}
|
||||
|
||||
void GuildRemoveAction::SendPacket(WorldPacket packet)
|
||||
{
|
||||
WorldPackets::Guild::GuildOfficerRemoveMember data = WorldPacket(packet);
|
||||
bot->GetSession()->HandleGuildRemoveOpcode(data);
|
||||
}
|
||||
|
||||
bool GuildRemoveAction::PlayerIsValid(Player* member)
|
||||
{
|
||||
return member->GetGuildId() == bot->GetGuildId() && GetRankId(bot) < GetRankId(member);
|
||||
|
||||
Reference in New Issue
Block a user