feat(Core/Hooks): added collection of hooks to extends AC (#3047)

This collection of hooks comes from the Maelstrom project. It allows to release modules such as :
- 3v3-soloqueue
- 1v1 arena
- pvestats

and many others
This commit is contained in:
Kargatum
2021-04-13 18:26:39 +07:00
committed by GitHub
parent 911fbb377e
commit 2b3d46bd4f
46 changed files with 2053 additions and 278 deletions

View File

@@ -101,6 +101,9 @@ bool ArenaTeam::AddMember(uint64 playerGuid)
playerClass = playerData->playerClass;
}
if (!sScriptMgr->CanAddMember(this, playerGuid))
return false;
// Check if player is already in a similar arena team
if ((player && player->GetArenaTeamId(GetSlot())) || Player::GetArenaTeamIdFromStorage(GUID_LOPART(playerGuid), GetSlot()) != 0)
{
@@ -610,27 +613,24 @@ void ArenaTeam::MassInviteToEvent(WorldSession* session)
uint8 ArenaTeam::GetSlotByType(uint32 type)
{
uint8 slot = 0xFF;
switch (type)
auto const& itr = ArenaSlotByType.find(type);
if (itr == ArenaSlotByType.end())
{
case ARENA_TEAM_2v2:
slot = 0;
break;
case ARENA_TEAM_3v3:
slot = 1;
break;
case ARENA_TEAM_5v5:
slot = 2;
break;
default:
break;
sLog->outError("FATAL: Unknown arena team type %u for some arena team", type);
return slot;
}
//Get the changed slot type
slot = ArenaSlotByType.at(type);
// Get the changed slot type
sScriptMgr->OnGetSlotByType(type, slot);
if (slot != 0xFF)
{
return slot;
}
sLog->outError("FATAL: Unknown arena team type %u for some arena team", type);
return 0xFF;
}
@@ -868,12 +868,14 @@ void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32
{
// update personal rating
int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, true);
sScriptMgr->OnBeforeUpdatingPersonalRating(mod, GetType());
itr->ModifyPersonalRating(player, mod, GetType());
// update matchmaker rating (pussywizard: but don't allow it to go over team rating)
if (itr->MatchMakerRating < Stats.Rating)
{
mod = std::min(MatchmakerRatingChange, Stats.Rating - itr->MatchMakerRating);
sScriptMgr->OnBeforeUpdatingPersonalRating(mod, GetType());
itr->ModifyMatchmakerRating(mod, GetSlot());
}
@@ -922,6 +924,9 @@ void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& playerPoints)
void ArenaTeam::SaveToDB()
{
if (!sScriptMgr->CanSaveToDB(this))
return;
// Save team and member stats to db
// Called after a match has ended or when calculating arena_points
@@ -997,3 +1002,83 @@ ArenaTeamMember* ArenaTeam::GetMember(uint64 guid)
return nullptr;
}
uint8 ArenaTeam::GetReqPlayersForType(uint32 type)
{
auto const& itr = ArenaReqPlayersForType.find(type);
if (itr == ArenaReqPlayersForType.end())
{
sLog->outError("FATAL: Unknown arena type %u!", type);
return 0xFF;
}
return ArenaReqPlayersForType.at(type);
}
void ArenaTeam::CreateTempArenaTeam(std::vector<Player*> playerList, uint8 type, std::string const& teamName)
{
auto playerCountInTeam = static_cast<uint32>(playerList.size());
ASSERT(playerCountInTeam == GetReqPlayersForType(type));
// Generate new arena team id
TeamId = sArenaTeamMgr->GenerateTempArenaTeamId();
// Assign member variables
CaptainGuid = playerList[0]->GetGUID();
Type = type;
TeamName = teamName;
BackgroundColor = 0;
EmblemStyle = 0;
EmblemColor = 0;
BorderStyle = 0;
BorderColor = 0;
Stats.WeekGames = 0;
Stats.SeasonGames = 0;
Stats.Rating = 0;
Stats.WeekWins = 0;
Stats.SeasonWins = 0;
for (auto const& _player : playerList)
{
ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(_player->GetArenaTeamId(GetSlotByType(type)));
if (!team)
continue;
ArenaTeamMember newMember;
for (auto const& itr : Members)
newMember = itr;
Stats.WeekGames += team->Stats.WeekGames;
Stats.SeasonGames += team->Stats.SeasonGames;
Stats.Rating += team->GetRating();
Stats.WeekWins += team->Stats.WeekWins;
Stats.SeasonWins += team->Stats.SeasonWins;
Members.push_back(newMember);
}
Stats.WeekGames /= playerCountInTeam;
Stats.SeasonGames /= playerCountInTeam;
Stats.Rating /= playerCountInTeam;
Stats.WeekWins /= playerCountInTeam;
Stats.SeasonWins /= playerCountInTeam;
}
// init/update unordered_map ArenaSlotByType
std::unordered_map<uint32, uint8> ArenaTeam::ArenaSlotByType =
{
{ ARENA_TEAM_2v2, ARENA_SLOT_2v2},
{ ARENA_TEAM_3v3, ARENA_SLOT_3v3},
{ ARENA_TEAM_5v5, ARENA_SLOT_5v5}
};
// init/update unordered_map ArenaReqPlayersForType
std::unordered_map<uint8, uint8> ArenaTeam::ArenaReqPlayersForType =
{
{ ARENA_TYPE_2v2, 4},
{ ARENA_TYPE_3v3, 6},
{ ARENA_TYPE_5v5, 10}
};

View File

@@ -58,6 +58,19 @@ enum ArenaTeamEvents
ERR_ARENA_TEAM_DISBANDED_S = 8 // captain name + arena team name
};
// PLAYER_FIELD_ARENA_TEAM_INFO_1_1 offsets
enum ArenaTeamInfoType
{
ARENA_TEAM_ID = 0,
ARENA_TEAM_TYPE = 1, // new in 3.2 - team type?
ARENA_TEAM_MEMBER = 2, // 0 - captain, 1 - member
ARENA_TEAM_GAMES_WEEK = 3,
ARENA_TEAM_GAMES_SEASON = 4,
ARENA_TEAM_WINS_SEASON = 5,
ARENA_TEAM_PERSONAL_RATING = 6,
ARENA_TEAM_END = 7
};
/*
need info how to send these ones:
ERR_ARENA_TEAM_YOU_JOIN_S - client show it automatically when accept invite
@@ -73,6 +86,13 @@ enum ArenaTeamTypes
ARENA_TEAM_5v5 = 5
};
enum ArenaSlot
{
ARENA_SLOT_2v2,
ARENA_SLOT_3v3,
ARENA_SLOT_5v5
};
struct ArenaTeamMember
{
uint64 Guid;
@@ -118,9 +138,11 @@ public:
[[nodiscard]] uint32 GetType() const { return Type; }
[[nodiscard]] uint8 GetSlot() const { return GetSlotByType(GetType()); }
static uint8 GetSlotByType(uint32 type);
static uint8 GetReqPlayersForType(uint32 type);
[[nodiscard]] uint64 GetCaptain() const { return CaptainGuid; }
[[nodiscard]] std::string const& GetName() const { return TeamName; }
[[nodiscard]] const ArenaTeamStats& GetStats() const { return Stats; }
void SetArenaTeamStats(ArenaTeamStats& stats) { Stats = stats; }
[[nodiscard]] uint32 GetRating() const { return Stats.Rating; }
uint32 GetAverageMMR(Group* group) const;
@@ -137,6 +159,7 @@ public:
[[nodiscard]] bool Empty() const { return Members.empty(); }
MemberList::iterator m_membersBegin() { return Members.begin(); }
MemberList::iterator m_membersEnd() { return Members.end(); }
MemberList& GetMembers() { return Members; }
[[nodiscard]] bool IsMember(uint64 guid) const;
ArenaTeamMember* GetMember(uint64 guid);
@@ -174,6 +197,12 @@ public:
void FinishWeek();
void FinishGame(int32 mod, const Map* bgMap);
void CreateTempArenaTeam(std::vector<Player*> playerList, uint8 type, std::string const& teamName);
// Containers
static std::unordered_map<uint32, uint8> ArenaSlotByType; // Slot -> Type
static std::unordered_map<uint8, uint8> ArenaReqPlayersForType; // Type -> Players count
protected:
uint32 TeamId;
uint8 Type;

View File

@@ -14,10 +14,14 @@
#include "ScriptMgr.h"
#include "World.h"
constexpr uint32 MAX_ARENA_TEAM_ID = 0xFFF00000;
constexpr uint32 MAX_TEMP_ARENA_TEAM_ID = 0xFFFFFFFE;
ArenaTeamMgr::ArenaTeamMgr()
{
NextArenaTeamId = 1;
LastArenaLogId = 0;
NextTempArenaTeamId = 0xFFF00000;
}
ArenaTeamMgr::~ArenaTeamMgr()
@@ -114,14 +118,23 @@ void ArenaTeamMgr::RemoveArenaTeam(uint32 arenaTeamId)
uint32 ArenaTeamMgr::GenerateArenaTeamId()
{
if (NextArenaTeamId >= 0xFFFFFFFE)
if (NextArenaTeamId >= MAX_ARENA_TEAM_ID)
{
sLog->outError("Arena team ids overflow!! Can't continue, shutting down server. ");
World::StopNow(ERROR_EXIT_CODE);
}
return NextArenaTeamId++;
}
uint32 ArenaTeamMgr::GenerateTempArenaTeamId()
{
if (NextTempArenaTeamId >= MAX_TEMP_ARENA_TEAM_ID)
NextTempArenaTeamId = MAX_ARENA_TEAM_ID;
return NextTempArenaTeamId++;
}
void ArenaTeamMgr::LoadArenaTeams()
{
uint32 oldMSTime = getMSTime();

View File

@@ -31,6 +31,7 @@ public:
ArenaTeamContainer::iterator GetArenaTeamMapBegin() { return ArenaTeamStore.begin(); }
ArenaTeamContainer::iterator GetArenaTeamMapEnd() { return ArenaTeamStore.end(); }
ArenaTeamContainer& GetArenaTeams() { return ArenaTeamStore; }
void DistributeArenaPoints();
@@ -40,8 +41,11 @@ public:
uint32 GetNextArenaLogId() { return ++LastArenaLogId; }
void SetLastArenaLogId(uint32 id) { LastArenaLogId = id; }
uint32 GenerateTempArenaTeamId();
protected:
uint32 NextArenaTeamId;
uint32 NextTempArenaTeamId;
ArenaTeamContainer ArenaTeamStore;
uint32 LastArenaLogId;
};

View File

@@ -1382,7 +1382,7 @@ void Battleground::ReadyMarkerClicked(Player* p)
return;
readyMarkerClickedSet.insert(p->GetGUIDLow());
uint32 count = readyMarkerClickedSet.size();
uint32 req = GetArenaType() * 2;
uint32 req = ArenaTeam::GetReqPlayersForType(GetArenaType());
p->GetSession()->SendNotification("You are marked as ready %u/%u", count, req);
if (count == req)
{

View File

@@ -468,19 +468,7 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
// Set up correct min/max player counts for scoreboards
if (bg->isArena())
{
uint32 maxPlayersPerTeam = 0;
switch (arenaType)
{
case ARENA_TYPE_2v2:
maxPlayersPerTeam = 2;
break;
case ARENA_TYPE_3v3:
maxPlayersPerTeam = 3;
break;
case ARENA_TYPE_5v5:
maxPlayersPerTeam = 5;
break;
}
uint32 maxPlayersPerTeam = ArenaTeam::GetReqPlayersForType(arenaType) / 2;
sScriptMgr->OnSetArenaMaxPlayersPerTeam(arenaType, maxPlayersPerTeam);
bg->SetMaxPlayersPerTeam(maxPlayersPerTeam);
}
@@ -748,31 +736,24 @@ bool BattlegroundMgr::IsArenaType(BattlegroundTypeId bgTypeId)
BattlegroundQueueTypeId BattlegroundMgr::BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 arenaType)
{
if (arenaType) {
uint32 queueTypeID = BATTLEGROUND_QUEUE_NONE;
switch (arenaType) {
case ARENA_TYPE_2v2:
queueTypeID = BATTLEGROUND_QUEUE_2v2;
break;
case ARENA_TYPE_3v3:
queueTypeID = BATTLEGROUND_QUEUE_3v3;
break;
case ARENA_TYPE_5v5:
queueTypeID = BATTLEGROUND_QUEUE_5v5;
break;
default:
break;
}
sScriptMgr->OnArenaTypeIDToQueueID(bgTypeId, arenaType, queueTypeID);
return BattlegroundQueueTypeId(queueTypeID);
}
uint32 queueTypeID = BATTLEGROUND_QUEUE_NONE;
if (BattlegroundMgr::bgToQueue.find(bgTypeId) == BattlegroundMgr::bgToQueue.end())
if (arenaType)
{
return BATTLEGROUND_QUEUE_NONE;
if (BattlegroundMgr::ArenaTypeToQueue.find(arenaType) != BattlegroundMgr::ArenaTypeToQueue.end())
{
queueTypeID = BattlegroundMgr::ArenaTypeToQueue.at(arenaType);
}
sScriptMgr->OnArenaTypeIDToQueueID(bgTypeId, arenaType, queueTypeID);
}
return BattlegroundMgr::bgToQueue[bgTypeId];
if (BattlegroundMgr::bgToQueue.find(bgTypeId) != BattlegroundMgr::bgToQueue.end())
{
queueTypeID = BattlegroundMgr::bgToQueue.at(bgTypeId);
}
return static_cast<BattlegroundQueueTypeId>(queueTypeID);
}
BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueueTypeId)
@@ -788,21 +769,14 @@ BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueue
uint8 BattlegroundMgr::BGArenaType(BattlegroundQueueTypeId bgQueueTypeId)
{
uint8 arenaType = 0;
switch (bgQueueTypeId)
if (BattlegroundMgr::QueueToArenaType.find(bgQueueTypeId) != BattlegroundMgr::QueueToArenaType.end())
{
case BATTLEGROUND_QUEUE_2v2:
arenaType = ARENA_TYPE_2v2;
break;
case BATTLEGROUND_QUEUE_3v3:
arenaType = ARENA_TYPE_3v3;
break;
case BATTLEGROUND_QUEUE_5v5:
arenaType = ARENA_TYPE_5v5;
break;
default:
break;
arenaType = BattlegroundMgr::QueueToArenaType.at(bgQueueTypeId);
}
sScriptMgr->OnArenaQueueIdToArenaType(bgQueueTypeId, arenaType);
return arenaType;
}
@@ -1166,3 +1140,17 @@ std::unordered_map<int, bgTypeRef> BattlegroundMgr::getBgFromTypeID =
}
}
};
std::unordered_map<uint32, BattlegroundQueueTypeId> BattlegroundMgr::ArenaTypeToQueue =
{
{ ARENA_TYPE_2v2, BATTLEGROUND_QUEUE_2v2 },
{ ARENA_TYPE_3v3, BATTLEGROUND_QUEUE_3v3 },
{ ARENA_TYPE_5v5, BATTLEGROUND_QUEUE_5v5 }
};
std::unordered_map<uint32, ArenaType> BattlegroundMgr::QueueToArenaType =
{
{ BATTLEGROUND_QUEUE_2v2, ARENA_TYPE_2v2 },
{ BATTLEGROUND_QUEUE_3v3, ARENA_TYPE_3v3 },
{ BATTLEGROUND_QUEUE_5v5, ARENA_TYPE_5v5 }
};

View File

@@ -127,6 +127,8 @@ public:
static std::unordered_map<int, bgRef> bgTypeToTemplate; // BattlegroundTypeId -> bgRef
static std::unordered_map<int, bgMapRef> getBgFromMap; // BattlegroundMapID -> bgMapRef
static std::unordered_map<int, bgTypeRef> getBgFromTypeID; // BattlegroundTypeID -> bgTypeRef
static std::unordered_map<uint32, BattlegroundQueueTypeId> ArenaTypeToQueue; // ArenaType -> BattlegroundQueueTypeId
static std::unordered_map<uint32, ArenaType> QueueToArenaType; // BattlegroundQueueTypeId -> ArenaType
private:
bool CreateBattleground(CreateBattlegroundData& data);

View File

@@ -152,9 +152,7 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, PvPDiffi
ginfo->_groupType = index;
// announce world (this doesn't need mutex)
if (isRated && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(arenateamid))
sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, team->GetName().c_str(), ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
SendMessageArenaQueue(ginfo, true);
//add players from group to ginfo
if (grp)
@@ -185,7 +183,7 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, PvPDiffi
return ginfo;
if (!isRated && !isPremade && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
SendMessageQueue(leader, bg, bracketEntry);
SendMessageBGQueue(leader, bg, bracketEntry);
return ginfo;
}
@@ -298,9 +296,7 @@ void BattlegroundQueue::RemovePlayer(uint64 guid, bool sentToBg, uint32 playerQu
m_QueuedPlayers.erase(itr);
// announce to world if arena team left queue for rated match, show only once
if (groupInfo->ArenaType && groupInfo->IsRated && groupInfo->Players.empty() && sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(groupInfo->ArenaTeamId))
sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, team->GetName().c_str(), groupInfo->ArenaType, groupInfo->ArenaType, groupInfo->ArenaTeamRating);
SendMessageArenaQueue(groupInfo, false);
// if player leaves queue and he is invited to a rated arena match, then count it as he lost
if (groupInfo->IsInvitedToBGInstanceGUID && groupInfo->IsRated && !sentToBg)
@@ -726,6 +722,8 @@ void BattlegroundQueue::BattlegroundQueueUpdate(BattlegroundBracketId bracket_id
MaxPlayersPerTeam = m_arenaType;
}
sScriptMgr->OnQueueUpdate(this, bracket_id, isRated, arenaRatedTeamId);
// check if can start new premade battleground
if (bg_template->isBattleground() && m_bgTypeId != BATTLEGROUND_RB)
if (CheckPremadeMatch(bracket_id, MinPlayersPerTeam, MaxPlayersPerTeam))
@@ -963,9 +961,9 @@ bool BattlegroundQueue::IsAllQueuesEmpty(BattlegroundBracketId bracket_id)
return queueEmptyCount == BG_QUEUE_MAX;
}
void BattlegroundQueue::SendMessageQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry)
void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry)
{
if (!sScriptMgr->CanSendMessageQueue(this, leader, bg, bracketEntry))
if (!sScriptMgr->CanSendMessageBGQueue(this, leader, bg, bracketEntry))
return;
BattlegroundBracketId bracketId = bracketEntry->GetBracketId();
@@ -1004,6 +1002,32 @@ void BattlegroundQueue::SendMessageQueue(Player* leader, Battleground* bg, PvPDi
}
}
void BattlegroundQueue::SendMessageArenaQueue(GroupQueueInfo* ginfo, bool IsJoin)
{
if (!sWorld->getBoolConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE))
return;
if (!sScriptMgr->CanSendMessageArenaQueue(this, ginfo, IsJoin))
return;
ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(ginfo->ArenaTeamId);
if (!team)
return;
if (!ginfo->IsRated)
return;
uint8 ArenaType = ginfo->ArenaType;
uint32 ArenaTeamRating = ginfo->ArenaTeamRating;
std::string TeamName = team->GetName();
if (IsJoin)
sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating);
if (!IsJoin && ArenaType && ginfo->Players.empty())
sWorld->SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, TeamName.c_str(), ArenaType, ArenaType, ArenaTeamRating);
}
/*********************************************************/
/*** BATTLEGROUND QUEUE EVENTS ***/
/*********************************************************/

View File

@@ -71,7 +71,8 @@ public:
uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo) const;
uint32 GetPlayersCountInGroupsQueue(BattlegroundBracketId bracketId, BattlegroundQueueGroupTypes bgqueue);
bool IsAllQueuesEmpty(BattlegroundBracketId bracket_id);
void SendMessageQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry);
void SendMessageBGQueue(Player* leader, Battleground* bg, PvPDifficultyEntry const* bracketEntry);
void SendMessageArenaQueue(GroupQueueInfo* ginfo, bool IsJoin);
void SetBgTypeIdAndArenaType(BattlegroundTypeId b, uint8 a) { m_bgTypeId = b; m_arenaType = ArenaType(a); } // pussywizard
void AddEvent(BasicEvent* Event, uint64 e_time);
@@ -110,6 +111,9 @@ public:
//one selection pool for horde, other one for alliance
SelectionPool m_SelectionPools[BG_TEAMS_COUNT];
ArenaType GetArenaType() { return m_arenaType; }
BattlegroundTypeId GetBGTypeID() { return m_bgTypeId; }
private:
BattlegroundTypeId m_bgTypeId;
ArenaType m_arenaType;