feat(Core/Arena): swap OnGetStartPersonalRating for OnAddMember, add OnArenaWeekReset (#27512)

This commit is contained in:
Stefano Borzì
2026-09-07 17:00:34 +02:00
committed by GitHub
parent b53c5576a9
commit c665359412
9 changed files with 53 additions and 17 deletions
@@ -278,7 +278,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
// Arena teams // Arena teams
PrepareStatement(CHAR_INS_ARENA_TEAM, "INSERT INTO arena_team (arenaTeamId, name, captainGuid, type, rating, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ARENA_TEAM, "INSERT INTO arena_team (arenaTeamId, name, captainGuid, type, rating, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ARENA_TEAM_MEMBER, "INSERT INTO arena_team_member (arenaTeamId, guid, personalRating) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ARENA_TEAM_MEMBER, "INSERT INTO arena_team_member (arenaTeamId, guid, weekGames, weekWins, seasonGames, seasonWins, personalRating) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ARENA_TEAM, "DELETE FROM arena_team WHERE arenaTeamId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ARENA_TEAM, "DELETE FROM arena_team WHERE arenaTeamId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ARENA_TEAM_MEMBERS, "DELETE FROM arena_team_member WHERE arenaTeamId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ARENA_TEAM_MEMBERS, "DELETE FROM arena_team_member WHERE arenaTeamId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ARENA_TEAM_CAPTAIN, "UPDATE arena_team SET captainGuid = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ARENA_TEAM_CAPTAIN, "UPDATE arena_team SET captainGuid = ? WHERE arenaTeamId = ?", CONNECTION_ASYNC);
+7 -3
View File
@@ -137,8 +137,6 @@ bool ArenaTeam::AddMember(ObjectGuid playerGuid)
else if (GetRating() >= 1000) else if (GetRating() >= 1000)
personalRating = 1000; personalRating = 1000;
sScriptMgr->OnGetStartPersonalRating(this, playerGuid, personalRating);
// xinef: sync query // xinef: sync query
// Try to get player's match maker rating from db and fall back to config setting if not found // Try to get player's match maker rating from db and fall back to config setting if not found
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MATCH_MAKER_RATING); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MATCH_MAKER_RATING);
@@ -177,6 +175,8 @@ bool ArenaTeam::AddMember(ObjectGuid playerGuid)
newMember.MatchMakerRating = matchMakerRating; newMember.MatchMakerRating = matchMakerRating;
newMember.MaxMMR = maxMMR; newMember.MaxMMR = maxMMR;
sScriptMgr->OnAddMember(this, newMember);
Members.push_back(newMember); Members.push_back(newMember);
sCharacterCache->UpdateCharacterArenaTeamId(playerGuid, GetSlot(), GetId()); sCharacterCache->UpdateCharacterArenaTeamId(playerGuid, GetSlot(), GetId());
@@ -184,7 +184,11 @@ bool ArenaTeam::AddMember(ObjectGuid playerGuid)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM_MEMBER); stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM_MEMBER);
stmt->SetData(0, TeamId); stmt->SetData(0, TeamId);
stmt->SetData(1, playerGuid.GetCounter()); stmt->SetData(1, playerGuid.GetCounter());
stmt->SetData(2, personalRating); stmt->SetData(2, newMember.WeekGames);
stmt->SetData(3, newMember.WeekWins);
stmt->SetData(4, newMember.SeasonGames);
stmt->SetData(5, newMember.SeasonWins);
stmt->SetData(6, newMember.PersonalRating);
CharacterDatabase.Execute(stmt); CharacterDatabase.Execute(stmt);
// Inform player if online // Inform player if online
@@ -268,6 +268,8 @@ void ArenaTeamMgr::DistributeArenaPoints()
} }
} }
sScriptMgr->OnArenaWeekReset();
ChatHandler(nullptr).SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END); ChatHandler(nullptr).SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
ChatHandler(nullptr).SendWorldText(LANG_DIST_ARENA_POINTS_END); ChatHandler(nullptr).SendWorldText(LANG_DIST_ARENA_POINTS_END);
@@ -54,9 +54,9 @@ bool ScriptMgr::CanSaveArenaStatsForMember(ArenaTeam* team, ObjectGuid playerGui
CALL_ENABLED_BOOLEAN_HOOKS(ArenaScript, ARENAHOOK_CAN_SAVE_ARENA_STATS_FOR_MEMBER, !script->CanSaveArenaStatsForMember(team, playerGuid)); CALL_ENABLED_BOOLEAN_HOOKS(ArenaScript, ARENAHOOK_CAN_SAVE_ARENA_STATS_FOR_MEMBER, !script->CanSaveArenaStatsForMember(team, playerGuid));
} }
void ScriptMgr::OnGetStartPersonalRating(ArenaTeam* team, ObjectGuid playerGuid, uint32& personalRating) void ScriptMgr::OnAddMember(ArenaTeam* team, ArenaTeamMember& member)
{ {
CALL_ENABLED_HOOKS(ArenaScript, ARENAHOOK_ON_GET_START_PERSONAL_RATING, script->OnGetStartPersonalRating(team, playerGuid, personalRating)); CALL_ENABLED_HOOKS(ArenaScript, ARENAHOOK_ON_ADD_MEMBER, script->OnAddMember(team, member));
} }
ArenaScript::ArenaScript(char const* name, std::vector<uint16> enabledHooks) ArenaScript::ArenaScript(char const* name, std::vector<uint16> enabledHooks)
@@ -22,6 +22,8 @@
#include "ScriptObject.h" #include "ScriptObject.h"
#include <vector> #include <vector>
struct ArenaTeamMember;
enum ArenaHook enum ArenaHook
{ {
ARENAHOOK_CAN_ADD_MEMBER, ARENAHOOK_CAN_ADD_MEMBER,
@@ -31,7 +33,7 @@ enum ArenaHook
ARENAHOOK_ON_ARENA_START, ARENAHOOK_ON_ARENA_START,
ARENAHOOK_ON_BEFORE_TEAM_MEMBER_UPDATE, ARENAHOOK_ON_BEFORE_TEAM_MEMBER_UPDATE,
ARENAHOOK_CAN_SAVE_ARENA_STATS_FOR_MEMBER, ARENAHOOK_CAN_SAVE_ARENA_STATS_FOR_MEMBER,
ARENAHOOK_ON_GET_START_PERSONAL_RATING, ARENAHOOK_ON_ADD_MEMBER,
ARENAHOOK_END ARENAHOOK_END
}; };
@@ -59,9 +61,13 @@ public:
[[nodiscard]] virtual bool CanSaveArenaStatsForMember(ArenaTeam* /*team*/, ObjectGuid /*playerGuid*/) { return true; } [[nodiscard]] virtual bool CanSaveArenaStatsForMember(ArenaTeam* /*team*/, ObjectGuid /*playerGuid*/) { return true; }
// Called with the personal rating the core computed for a player joining the team, before it is // Called with the fully built member right before it is added to the team and written to
// stored on the member and written to arena_team_member. // arena_team_member. The personal rating and the week/season counters left on the struct are
virtual void OnGetStartPersonalRating(ArenaTeam* /*team*/, ObjectGuid /*playerGuid*/, uint32& /*personalRating*/) { } // what the team holds and what is stored. MatchMakerRating and MaxMMR are held in memory but
// not written here, only by the next ArenaTeam::SaveToDB; Guid, Name and Class are identity,
// and changing them desyncs the member from its row and the character cache.
// Cannot veto the join, CanAddMember does that.
virtual void OnAddMember(ArenaTeam* /*team*/, ArenaTeamMember& /*member*/) { }
}; };
#endif #endif
@@ -74,6 +74,11 @@ void ScriptMgr::OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<ObjectGuid, ui
CALL_ENABLED_HOOKS(GlobalScript, GLOBALHOOK_ON_BEFORE_UPDATE_ARENA_POINTS, script->OnBeforeUpdateArenaPoints(at, ap)); CALL_ENABLED_HOOKS(GlobalScript, GLOBALHOOK_ON_BEFORE_UPDATE_ARENA_POINTS, script->OnBeforeUpdateArenaPoints(at, ap));
} }
void ScriptMgr::OnArenaWeekReset()
{
CALL_ENABLED_HOOKS(GlobalScript, GLOBALHOOK_ON_ARENA_WEEK_RESET, script->OnArenaWeekReset());
}
void ScriptMgr::OnAfterUpdateEncounterState(Map* map, EncounterCreditType type, uint32 creditEntry, Unit* source, Difficulty difficulty_fixed, DungeonEncounterList const* encounters, uint32 dungeonCompleted, bool updated) void ScriptMgr::OnAfterUpdateEncounterState(Map* map, EncounterCreditType type, uint32 creditEntry, Unit* source, Difficulty difficulty_fixed, DungeonEncounterList const* encounters, uint32 dungeonCompleted, bool updated)
{ {
CALL_ENABLED_HOOKS(GlobalScript, GLOBALHOOK_ON_AFTER_UPDATE_ENCOUNTER_STATE, script->OnAfterUpdateEncounterState(map, type, creditEntry, source, difficulty_fixed, encounters, dungeonCompleted, updated)); CALL_ENABLED_HOOKS(GlobalScript, GLOBALHOOK_ON_AFTER_UPDATE_ENCOUNTER_STATE, script->OnAfterUpdateEncounterState(map, type, creditEntry, source, difficulty_fixed, encounters, dungeonCompleted, updated));
@@ -37,6 +37,7 @@ enum GlobalHook
GLOBALHOOK_ON_INITIALIZE_LOCKED_DUNGEONS, GLOBALHOOK_ON_INITIALIZE_LOCKED_DUNGEONS,
GLOBALHOOK_ON_AFTER_INITIALIZE_LOCKED_DUNGEONS, GLOBALHOOK_ON_AFTER_INITIALIZE_LOCKED_DUNGEONS,
GLOBALHOOK_ON_BEFORE_UPDATE_ARENA_POINTS, GLOBALHOOK_ON_BEFORE_UPDATE_ARENA_POINTS,
GLOBALHOOK_ON_ARENA_WEEK_RESET,
GLOBALHOOK_ON_AFTER_UPDATE_ENCOUNTER_STATE, GLOBALHOOK_ON_AFTER_UPDATE_ENCOUNTER_STATE,
GLOBALHOOK_ON_BEFORE_WORLDOBJECT_SET_PHASEMASK, GLOBALHOOK_ON_BEFORE_WORLDOBJECT_SET_PHASEMASK,
GLOBALHOOK_ON_IS_AFFECTED_BY_SPELL_MOD_CHECK, GLOBALHOOK_ON_IS_AFFECTED_BY_SPELL_MOD_CHECK,
@@ -73,6 +74,10 @@ public:
// On Before arena points distribution // On Before arena points distribution
virtual void OnBeforeUpdateArenaPoints(ArenaTeam* /*at*/, std::map<ObjectGuid, uint32>& /*ap*/) { } virtual void OnBeforeUpdateArenaPoints(ArenaTeam* /*at*/, std::map<ObjectGuid, uint32>& /*ap*/) { }
// Called when the weekly arena point distribution has just reset the week statistics of every
// arena team on the realm.
virtual void OnArenaWeekReset() { }
// Called when a dungeon encounter is updated. // Called when a dungeon encounter is updated.
virtual void OnAfterUpdateEncounterState(Map* /*map*/, EncounterCreditType /*type*/, uint32 /*creditEntry*/, Unit* /*source*/, Difficulty /*difficulty_fixed*/, std::list<DungeonEncounter const*> const* /*encounters*/, uint32 /*dungeonCompleted*/, bool /*updated*/) { } virtual void OnAfterUpdateEncounterState(Map* /*map*/, EncounterCreditType /*type*/, uint32 /*creditEntry*/, Unit* /*source*/, Difficulty /*difficulty_fixed*/, std::list<DungeonEncounter const*> const* /*encounters*/, uint32 /*dungeonCompleted*/, bool /*updated*/) { }
+2 -1
View File
@@ -522,6 +522,7 @@ public: /* GlobalScript */
void OnGlobalItemDelFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid); void OnGlobalItemDelFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid);
void OnGlobalMirrorImageDisplayItem(Item const* item, uint32& display); void OnGlobalMirrorImageDisplayItem(Item const* item, uint32& display);
void OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<ObjectGuid, uint32>& ap); void OnBeforeUpdateArenaPoints(ArenaTeam* at, std::map<ObjectGuid, uint32>& ap);
void OnArenaWeekReset();
void OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32& maxcount, LootStore const& store); void OnAfterRefCount(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, uint32& maxcount, LootStore const& store);
void OnAfterCalculateLootGroupAmount(Player const* player, Loot& loot, uint16 lootMode, uint32& groupAmount, LootStore const& store); void OnAfterCalculateLootGroupAmount(Player const* player, Loot& loot, uint16 lootMode, uint32& groupAmount, LootStore const& store);
void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store); void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* LootStoreItem, LootStore const& store);
@@ -675,7 +676,7 @@ public: /* ArenaScript */
void OnArenaStart(Battleground* const bg); void OnArenaStart(Battleground* const bg);
bool OnBeforeArenaTeamMemberUpdate(ArenaTeam* team, Player* player, bool won, uint32 opponentMatchmakerRating, int32 matchmakerChange); bool OnBeforeArenaTeamMemberUpdate(ArenaTeam* team, Player* player, bool won, uint32 opponentMatchmakerRating, int32 matchmakerChange);
bool CanSaveArenaStatsForMember(ArenaTeam* team, ObjectGuid playerGuid); bool CanSaveArenaStatsForMember(ArenaTeam* team, ObjectGuid playerGuid);
void OnGetStartPersonalRating(ArenaTeam* team, ObjectGuid playerGuid, uint32& personalRating); void OnAddMember(ArenaTeam* team, ArenaTeamMember& member);
public: /* MiscScript */ public: /* MiscScript */
@@ -92,14 +92,27 @@ TEST_F(ArenaHookDefaultsTest, CanSaveArenaStatsForMemberDefaultsTrue)
EXPECT_TRUE(sScriptMgr->CanSaveArenaStatsForMember(&team, ObjectGuid::Empty)); EXPECT_TRUE(sScriptMgr->CanSaveArenaStatsForMember(&team, ObjectGuid::Empty));
} }
// OnGetStartPersonalRating must leave the rating untouched by default so a new // OnAddMember must leave the member untouched by default so a new arena team
// arena team member keeps the value ArenaTeam::AddMember computed for them. // member keeps the rating and counters ArenaTeam::AddMember built for them,
TEST_F(ArenaHookDefaultsTest, OnGetStartPersonalRatingKeepsCoreValue) // which are also what is written to arena_team_member.
TEST_F(ArenaHookDefaultsTest, OnAddMemberLeavesMemberUntouched)
{ {
ArenaTeam team; ArenaTeam team;
uint32 personalRating = 1000;
sScriptMgr->OnGetStartPersonalRating(&team, ObjectGuid::Empty, personalRating); ArenaTeamMember member{};
EXPECT_EQ(personalRating, 1000u); member.PersonalRating = 1000;
member.WeekGames = 6;
member.WeekWins = 3;
member.SeasonGames = 40;
member.SeasonWins = 22;
sScriptMgr->OnAddMember(&team, member);
EXPECT_EQ(member.PersonalRating, 1000u);
EXPECT_EQ(member.WeekGames, 6u);
EXPECT_EQ(member.WeekWins, 3u);
EXPECT_EQ(member.SeasonGames, 40u);
EXPECT_EQ(member.SeasonWins, 22u);
} }
// OnBeforeArenaCheckWinConditions must return true by default so // OnBeforeArenaCheckWinConditions must return true by default so