diff --git a/sql/pvpstats patch/pvpstats_char.sql b/sql/pvpstats patch/pvpstats_char.sql new file mode 100644 index 0000000000..dcb7585db7 --- /dev/null +++ b/sql/pvpstats patch/pvpstats_char.sql @@ -0,0 +1,26 @@ +CREATE TABLE IF NOT EXISTS `pvpstats_battlegrounds` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `winner_faction` tinyint(4) NOT NULL, + `bracket_id` tinyint(3) unsigned NOT NULL, + `type` tinyint(3) unsigned NOT NULL, + `date` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `pvpstats_players` ( + `battleground_id` bigint(20) unsigned NOT NULL, + `character_guid` int(10) unsigned NOT NULL, + `winner` bit(1) NOT NULL, + `score_killing_blows` mediumint(8) unsigned NOT NULL, + `score_deaths` mediumint(8) unsigned NOT NULL, + `score_honorable_kills` mediumint(8) unsigned NOT NULL, + `score_bonus_honor` mediumint(8) unsigned NOT NULL, + `score_damage_done` mediumint(8) unsigned NOT NULL, + `score_healing_done` mediumint(8) unsigned NOT NULL, + `attr_1` mediumint(8) unsigned NOT NULL DEFAULT '0', + `attr_2` mediumint(8) unsigned NOT NULL DEFAULT '0', + `attr_3` mediumint(8) unsigned NOT NULL DEFAULT '0', + `attr_4` mediumint(8) unsigned NOT NULL DEFAULT '0', + `attr_5` mediumint(8) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`battleground_id`,`character_guid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 3300aab3ee..96abd76b66 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -731,6 +731,27 @@ void Battleground::EndBattleground(TeamId winnerTeamId) else SetWinner(TEAM_NEUTRAL); + PreparedStatement* stmt = nullptr; + uint64 battlegroundId = 1; + if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + if (result) + { + Field* fields = result->Fetch(); + battlegroundId = fields[0].GetUInt64() + 1; + } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND); + stmt->setUInt64(0, battlegroundId); + stmt->setUInt8(1, GetWinner()); + stmt->setUInt8(2, GetUniqueBracketId()); + stmt->setUInt8(3, GetBgTypeID()); + CharacterDatabase.Execute(stmt); + } + //we must set it this way, because end time is sent in packet! m_EndTime = TIME_TO_AUTOREMOVE; @@ -869,6 +890,7 @@ void Battleground::EndBattleground(TeamId winnerTeamId) { Player* player = itr->second; TeamId bgTeamId = player->GetBgTeamId(); + // should remove spirit of redemption if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); @@ -947,6 +969,29 @@ void Battleground::EndBattleground(TeamId winnerTeamId) player->GetSession()->SendPacket(&pvpLogData); + if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER); + BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUID()); + + stmt->setUInt32(0, battlegroundId); + stmt->setUInt32(1, player->GetGUIDHigh()); + stmt->setBool(2, bgTeamId == winnerTeamId); + stmt->setUInt32(3, score->second->GetKillingBlows()); + stmt->setUInt32(4, score->second->GetDeaths()); + stmt->setUInt32(5, score->second->GetHonorableKills()); + stmt->setUInt32(6, score->second->GetBonusHonor()); + stmt->setUInt32(7, score->second->GetDamageDone()); + stmt->setUInt32(8, score->second->GetHealingDone()); + stmt->setUInt32(9, score->second->GetAttr1()); + stmt->setUInt32(10, score->second->GetAttr2()); + stmt->setUInt32(11, score->second->GetAttr3()); + stmt->setUInt32(12, score->second->GetAttr4()); + stmt->setUInt32(13, score->second->GetAttr5()); + + CharacterDatabase.Execute(stmt); + } + WorldPacket data; sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetCurrentBattlegroundQueueSlot(), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), player->GetBgTeamId()); player->GetSession()->SendPacket(&data); @@ -1845,3 +1890,8 @@ void Battleground::RewardXPAtKill(Player* killer, Player* victim) if (sWorld->getBoolConfig(CONFIG_BG_XP_FOR_KILL) && killer && victim) killer->RewardPlayerAndGroupAtKill(victim, true); } + +uint8 Battleground::GetUniqueBracketId() const +{ + return GetMinLevel() / 10; +} \ No newline at end of file diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 3aaa88fec1..4fe1499565 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -257,6 +257,19 @@ struct BattlegroundScore uint32 DamageDone; uint32 HealingDone; Player* player; + + uint32 GetKillingBlows() const { return KillingBlows; } + uint32 GetDeaths() const { return Deaths; } + uint32 GetHonorableKills() const { return HonorableKills; } + uint32 GetBonusHonor() const { return BonusHonor; } + uint32 GetDamageDone() const { return DamageDone; } + uint32 GetHealingDone() const { return HealingDone; } + + virtual uint32 GetAttr1() const { return 0; } + virtual uint32 GetAttr2() const { return 0; } + virtual uint32 GetAttr3() const { return 0; } + virtual uint32 GetAttr4() const { return 0; } + virtual uint32 GetAttr5() const { return 0; } }; class ArenaLogEntryData @@ -559,6 +572,9 @@ class Battleground virtual TeamId GetPrematureWinner(); + // because BattleGrounds with different types and same level range has different m_BracketId + uint8 GetUniqueBracketId() const; + BattlegroundAV* ToBattlegroundAV() { if (GetBgTypeID() == BATTLEGROUND_AV) return reinterpret_cast(this); else return NULL; } BattlegroundAV const* ToBattlegroundAV() const { if (GetBgTypeID() == BATTLEGROUND_AV) return reinterpret_cast(this); else return NULL; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index c32936a765..654937a721 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -216,6 +216,9 @@ struct BattlegroundABScore : public BattlegroundScore ~BattlegroundABScore() { } uint32 BasesAssaulted; uint32 BasesDefended; + + uint32 GetAttr1() const final override { return BasesAssaulted; } + uint32 GetAttr2() const final override { return BasesDefended; } }; class BattlegroundAB : public Battleground diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index a6b7d4af97..a2a43d5cec 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1565,6 +1565,12 @@ struct BattlegroundAVScore : public BattlegroundScore uint32 MinesCaptured; uint32 LeadersKilled; uint32 SecondaryObjectives; + + uint32 GetAttr1() const final override { return GraveyardsAssaulted; } + uint32 GetAttr2() const final override { return GraveyardsDefended; } + uint32 GetAttr3() const final override { return TowersAssaulted; } + uint32 GetAttr4() const final override { return TowersDefended; } + uint32 GetAttr5() const final override { return MinesCaptured; } }; class BattlegroundAV : public Battleground diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index f502da9c7d..a42c44bab8 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -310,6 +310,8 @@ struct BattlegroundEYScore : public BattlegroundScore BattlegroundEYScore(Player* player) : BattlegroundScore(player), FlagCaptures(0) { } ~BattlegroundEYScore() { } uint32 FlagCaptures; + + uint32 GetAttr1() const final override { return FlagCaptures; } }; class BattlegroundEY : public Battleground diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index 027d2d85bd..87ffccff32 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -894,6 +894,9 @@ struct BattlegroundICScore : public BattlegroundScore ~BattlegroundICScore() { } uint32 BasesAssaulted; uint32 BasesDefended; + + uint32 GetAttr1() const final override { return BasesAssaulted; } + uint32 GetAttr2() const final override { return BasesDefended; } }; class BattlegroundIC : public Battleground diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 367e8dead7..a22e6366a0 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -27,6 +27,9 @@ struct BattlegroundSAScore : public BattlegroundScore ~BattlegroundSAScore() { } uint8 demolishers_destroyed; uint8 gates_destroyed; + + uint32 GetAttr1() const final override { return DemolishersDestroyed; } + uint32 GetAttr2() const final override { return GatesDestroyed; } }; #define BG_SA_FLAG_AMOUNT 3 diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index 71542ab2ef..a5aee6fbb6 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -142,6 +142,9 @@ struct BattlegroundWGScore : public BattlegroundScore ~BattlegroundWGScore() { } uint32 FlagCaptures; uint32 FlagReturns; + + uint32 GetAttr1() const final override { return FlagCaptures; } + uint32 GetAttr2() const final override { return FlagReturns; } }; class BattlegroundWS : public Battleground diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b85d5662c7..f026cba9b4 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1044,6 +1044,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfigMgr->GetBoolDefault("Battleground.CastDeserter", true); m_bool_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetBoolDefault("Battleground.QueueAnnouncer.Enable", false); + m_bool_configs[CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE] = sConfigMgr->GetBoolDefault("Battleground.StoreStatistics.Enable", false); m_int_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfigMgr->GetIntDefault ("Battleground.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS); m_int_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfigMgr->GetIntDefault ("Battleground.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS); m_bool_configs[CONFIG_BG_XP_FOR_KILL] = sConfigMgr->GetBoolDefault("Battleground.GiveXPForKills", false); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index dfb5f7102b..378bdfce09 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -128,6 +128,7 @@ enum WorldBoolConfigs CONFIG_DECLINED_NAMES_USED, CONFIG_BATTLEGROUND_CAST_DESERTER, CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE, + CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE, CONFIG_BG_XP_FOR_KILL, CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_ARENA_SEASON_IN_PROGRESS, diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 80ef19aea0..ecc1a82722 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -553,4 +553,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_CHAR_PET, "REPLACE INTO character_pet (id, entry, owner, modelid, CreatedBySpell, PetType, level, exp, Reactstate, name, renamed, slot, curhealth, curmana, curhappiness, savetime, abdata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + + // PvPstats + PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_PVPSTATS_BATTLEGROUND, "INSERT INTO pvpstats_battlegrounds (id, winner_faction, bracket_id, type, date) VALUES (?, ?, ?, ?, NOW())", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PVPSTATS_PLAYER, "INSERT INTO pvpstats_players (battleground_id, character_guid, winner, score_killing_blows, score_deaths, score_honorable_kills, score_bonus_honor, score_damage_done, score_healing_done, attr_1, attr_2, attr_3, attr_4, attr_5) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_PVPSTATS_FACTIONS_OVERALL, "SELECT winner_faction, COUNT(*) AS count FROM pvpstats_battlegrounds WHERE DATEDIFF(NOW(), date) < 7 GROUP BY winner_faction ORDER BY winner_faction ASC", CONNECTION_SYNCH); + } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index da9598e964..12d244630d 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -492,6 +492,11 @@ enum CharacterDatabaseStatements CHAR_INS_ITEMCONTAINER_SINGLE_ITEM, CHAR_DEL_ITEMCONTAINER_CONTAINER, + CHAR_SEL_PVPSTATS_MAXID, + CHAR_INS_PVPSTATS_BATTLEGROUND, + CHAR_INS_PVPSTATS_PLAYER, + CHAR_SEL_PVPSTATS_FACTIONS_OVERALL, + MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 52f39ef402..b2fdb520eb 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -2499,6 +2499,13 @@ Battleground.GiveXPForKills = 0 Battleground.Random.ResetHour = 6 +# Battleground.StoreStatistics.Enable +# Description: Store Battleground scores in the database. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Battleground.StoreStatistics.Enable = 0 + # ###################################################################################################