mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 09:07:19 +00:00
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>
94 lines
3.0 KiB
C++
94 lines
3.0 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#ifndef _PLAYERBOT_OPERATION_H
|
|
#define _PLAYERBOT_OPERATION_H
|
|
|
|
#include "Common.h"
|
|
#include "ObjectGuid.h"
|
|
#include <memory>
|
|
|
|
/**
|
|
* @brief Base class for thread-unsafe operations that must be executed in the world thread
|
|
*
|
|
* PlayerbotOperation represents an operation that needs to be deferred from a map thread
|
|
* to the world thread for safe execution. Examples include group modifications, LFG operations,
|
|
* guild operations, etc.
|
|
*
|
|
* Thread Safety:
|
|
* - The constructor and data members must be thread-safe (use copies, not pointers)
|
|
* - Execute() is called in the world thread and can safely perform thread-unsafe operations
|
|
* - Subclasses must not store raw pointers to (core/world thread) game object (use ObjectGuid instead)
|
|
*/
|
|
class PlayerbotOperation
|
|
{
|
|
public:
|
|
virtual ~PlayerbotOperation() = default;
|
|
|
|
/**
|
|
* @brief Execute this operation in the world thread
|
|
*
|
|
* This method is called by PlayerbotWorldThreadProcessor::Update() which runs in the world thread.
|
|
* It's safe to perform any thread-unsafe operation here (Group, LFG, Guild, etc.)
|
|
*
|
|
* @return true if operation succeeded, false if it failed
|
|
*/
|
|
virtual bool Execute() = 0;
|
|
|
|
/**
|
|
* @brief Get the bot GUID this operation is for (optional)
|
|
*
|
|
* Used for logging and debugging purposes.
|
|
*
|
|
* @return ObjectGuid of the bot, or ObjectGuid::Empty if not applicable
|
|
*/
|
|
virtual ObjectGuid GetBotGuid() const { return ObjectGuid::Empty; }
|
|
|
|
/**
|
|
* @brief Get the operation priority (higher = more urgent)
|
|
*
|
|
* Priority levels:
|
|
* - 100: Critical (crash prevention, cleanup operations)
|
|
* - 50: High (player-facing operations like group invites)
|
|
* - 10: Normal (background operations)
|
|
* - 0: Low (statistics, logging)
|
|
*
|
|
* @return Priority value (0-100)
|
|
*/
|
|
virtual uint32 GetPriority() const { return 10; }
|
|
|
|
/**
|
|
* @brief Get a human-readable name for this operation
|
|
*
|
|
* Used for logging and debugging.
|
|
*
|
|
* @return Operation name
|
|
*/
|
|
virtual std::string GetName() const { return "Unknown Operation"; }
|
|
|
|
/**
|
|
* @brief Check if this operation is still valid
|
|
*
|
|
* Called before Execute() to check if the operation should still be executed.
|
|
* For example, if a bot logged out, group invite operations for that bot can be skipped.
|
|
*
|
|
* @return true if operation should be executed, false to skip
|
|
*/
|
|
virtual bool IsValid() const { return true; }
|
|
};
|
|
|
|
/**
|
|
* @brief Comparison operator for priority queue (higher priority first)
|
|
*/
|
|
struct PlayerbotOperationComparator
|
|
{
|
|
bool operator()(const std::unique_ptr<PlayerbotOperation>& a, const std::unique_ptr<PlayerbotOperation>& b) const
|
|
{
|
|
return a->GetPriority() < b->GetPriority(); // Lower priority goes to back of queue
|
|
}
|
|
};
|
|
|
|
#endif
|