Skip to content

Commit 687a85b

Browse files
committed
feat: mulligan instrumentation
1 parent 1dfa50b commit 687a85b

File tree

4 files changed

+133
-16
lines changed

4 files changed

+133
-16
lines changed

Hearthstone Deck Tracker/GameEventHandler.cs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,19 @@ public void HandlePlayerMulliganDone()
10231023
Core.Overlay.BattlegroundsHeroPickingViewModel.Reset();
10241024
}
10251025
else if(_game.IsConstructedMatch)
1026+
{
10261027
Core.Overlay.HideMulliganPanel(false);
1028+
_game.SnapshotOpeningHand();
1029+
CaptureMulliganGuideFeedback();
1030+
}
1031+
}
1032+
1033+
public void HandlePlayerSendChoices(Choice choice)
1034+
{
1035+
if(choice.ChoiceType == ChoiceType.MULLIGAN)
1036+
{
1037+
_game.SnapshotMulliganChoices(choice);
1038+
}
10271039
}
10281040

10291041
private async void HandleConstructedStart()
@@ -1042,25 +1054,15 @@ private async void HandleConstructedStart()
10421054
// Wait for the game to fade in
10431055
await Task.Delay(3000);
10441056

1057+
_game.SnapshotMulligan();
10451058

10461059
var shortId = DeckList.Instance.ActiveDeckVersion?.ShortId;
10471060
if(!string.IsNullOrEmpty(shortId))
10481061
{
1049-
var cards = Core.Game.Player.PlayerEntities.Where(x => x.IsInHand && !x.Info.Created).Select(x => x.Card.DbfId);
1050-
var opponentClass = Core.Game.Opponent.PlayerEntities.FirstOrDefault(x => x.IsHero && x.IsInPlay)?.Card.CardClass ?? CardClass.INVALID;
1051-
var hasCoin = Core.Game.Player.HasCoin;
1052-
1053-
var isWild = _game.CurrentFormat == Format.Wild;
1054-
var isClassic = _game.CurrentFormat == Format.Classic;
1055-
var isTwist = _game.CurrentFormat == Format.Twist;
1056-
1057-
var playerStarLevel = 0;
1058-
if (_game.MatchInfo != null)
1059-
{
1060-
var localPlayer = _game.MatchInfo.LocalPlayer;
1061-
var playerInfo = isClassic ? localPlayer.Classic : isWild ? localPlayer.Wild : isTwist ? localPlayer.Twist : localPlayer.Standard;
1062-
playerStarLevel = playerInfo?.StarLevel ?? 0;
1063-
}
1062+
var cards = _game.Player.PlayerEntities.Where(x => x.IsInHand && !x.Info.Created).Select(x => x.Card.DbfId);
1063+
var opponentClass = _game.Opponent.PlayerEntities.FirstOrDefault(x => x.IsHero && x.IsInPlay)?.Card.CardClass ?? CardClass.INVALID;
1064+
var hasCoin = _game.Player.HasCoin;
1065+
var playerStarLevel = _game.PlayerMedalInfo?.StarLevel ?? 0;
10641066

10651067
Core.Overlay.ShowMulliganPanel(shortId!, cards.ToArray(), opponentClass, hasCoin, playerStarLevel);
10661068
}
@@ -1070,6 +1072,18 @@ private async void HandleConstructedStart()
10701072
}
10711073
}
10721074

1075+
private async Task CaptureMulliganGuideFeedback()
1076+
{
1077+
if(!Config.Instance.GoogleAnalytics || _game.Spectator)
1078+
return;
1079+
1080+
var parameters = _game.GetMulliganStatsParams();
1081+
if (parameters is null)
1082+
return;
1083+
1084+
await ApiWrapper.PostMulliganGuideFeedback(parameters);
1085+
}
1086+
10731087
private async void HandleBattlegroundsStart()
10741088
{
10751089
if(Config.Instance.ShowBattlegroundsToast)
@@ -1732,7 +1746,7 @@ public void HandleQuestRewardDatabaseId(int id, int value)
17321746
void IGameHandler.SetOpponentHero(string? cardId) => SetOpponentHero(cardId);
17331747
void IGameHandler.SetPlayerHero(string? cardId) => SetPlayerHero(cardId);
17341748
void IGameHandler.HandleOpponentHeroPower(string cardId, int turn) => HandleOpponentHeroPower(cardId, turn);
1735-
void IGameHandler.HandlePlayerSendChoices(Choice choice) {}
1749+
void IGameHandler.HandlePlayerSendChoices(Choice choice) => HandlePlayerSendChoices(choice);
17361750
void IGameHandler.TurnStart(ActivePlayer player, int turnNumber) => TurnStart(player, turnNumber);
17371751
void IGameHandler.HandleGameStart(DateTime timestamp) => HandleGameStart(timestamp);
17381752
void IGameHandler.HandleGameEnd(bool stateComplete) => HandleGameEnd(stateComplete);

Hearthstone Deck Tracker/Hearthstone/GameV2.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.Linq;
66
using System.Threading.Tasks;
7+
using HearthDb.Deckstrings;
78
using HearthDb.Enums;
89
using HearthMirror.Objects;
910
using Hearthstone_Deck_Tracker.Controls.Overlay.Battlegrounds.HeroPicking;
@@ -20,6 +21,7 @@
2021
using Hearthstone_Deck_Tracker.Utility.ValueMoments.Utility;
2122
using HSReplay;
2223
using HSReplay.OAuth.Data;
24+
using HSReplay.Requests;
2325

2426
#endregion
2527

@@ -36,6 +38,7 @@ public class GameV2 : IGame
3638
private BattlegroundRatingInfo? _battlegroundsRatingInfo;
3739
private MercenariesRatingInfo? _mercenariesRatingInfo;
3840
private BattlegroundsBoardState? _battlegroundsBoardState;
41+
private MulliganState? _mulliganState;
3942
private Dictionary<int, Dictionary<int, int>> _battlegroundsHeroLatestTavernUpTurn;
4043
private Dictionary<int, Dictionary<int, int>> _battlegroundsHeroTriplesByTier;
4144
internal QueueEvents QueueEvents { get; }
@@ -51,6 +54,7 @@ public GameV2()
5154
_battlegroundsBoardState = new BattlegroundsBoardState(this);
5255
_battlegroundsHeroLatestTavernUpTurn = new Dictionary<int, Dictionary<int, int>>();
5356
_battlegroundsHeroTriplesByTier = new Dictionary<int, Dictionary<int, int>>();
57+
_mulliganState = new MulliganState(this);
5458
QueueEvents = new(this);
5559
Reset();
5660
LiveDataManager.OnStreamingChecked += async streaming =>
@@ -209,6 +213,25 @@ public GameType CurrentGameType
209213
public MatchInfo MatchInfo => _matchInfo ?? (_matchInfo = HearthMirror.Reflection.Client.GetMatchInfo());
210214
private bool _matchInfoCacheInvalid = true;
211215

216+
public MatchInfo.MedalInfo? PlayerMedalInfo
217+
{
218+
get
219+
{
220+
var localPlayer = MatchInfo?.LocalPlayer;
221+
if(localPlayer is null || CurrentGameType != GameType.GT_RANKED)
222+
return null;
223+
224+
return CurrentFormat switch
225+
{
226+
Format.Wild => localPlayer.Wild,
227+
Format.Classic => localPlayer.Classic,
228+
Format.Twist => localPlayer.Twist,
229+
Format.Standard => localPlayer.Standard,
230+
_ => null,
231+
};
232+
}
233+
}
234+
212235
public BrawlInfo BrawlInfo => _brawlInfo ?? (_brawlInfo = HearthMirror.Reflection.Client.GetBrawlInfo());
213236

214237
public BattlegroundRatingInfo BattlegroundsRatingInfo => _battlegroundsRatingInfo ?? (_battlegroundsRatingInfo = HearthMirror.Reflection.Client.GetBattlegroundRatingInfo());
@@ -376,5 +399,32 @@ public void UpdateBattlegroundsPlayerTriples(int id, int value)
376399
{
377400
return _battlegroundsHeroTriplesByTier.TryGetValue(id, out var data) ? data : null;
378401
}
402+
403+
public void SnapshotOpeningHand() => _mulliganState?.SnapshotOpeningHand();
404+
public void SnapshotMulliganChoices(Choice choice) => _mulliganState?.SnapshotMulliganChoices(choice);
405+
public void SnapshotMulligan() => _mulliganState?.SnapshotMulligan();
406+
407+
public MulliganGuideFeedbackParams? GetMulliganStatsParams()
408+
{
409+
var activeDeck = DeckList.Instance.ActiveDeck;
410+
if(activeDeck == null)
411+
return null;
412+
413+
var opponentClass = Opponent.PlayerEntities.FirstOrDefault(x => x.IsHero && x.IsInPlay)?.Card.CardClass ?? CardClass.INVALID;
414+
var starLevel = PlayerMedalInfo?.StarLevel ?? 0;
415+
416+
return new MulliganGuideFeedbackParams
417+
{
418+
Deckstring = DeckSerializer.Serialize(HearthDbConverter.ToHearthDbDeck(activeDeck), false),
419+
OpponentClass = opponentClass.ToString(),
420+
PlayerInitiative = Player.HasCoin ? "COIN" : "FIRST",
421+
PlayerRegion = CurrentRegion != Region.UNKNOWN ? "REGION_" + CurrentRegion : null,
422+
PlayerStarLevel = starLevel > 0 ? starLevel : null,
423+
GameType = (int)HearthDbConverter.GetBnetGameType(CurrentGameType, CurrentFormat),
424+
OfferedCards = _mulliganState?.OfferedCards.Select(x => x.Card.DbfId).ToArray(),
425+
KeptCards = _mulliganState?.KeptCards.Select(x => x.Card.DbfId).ToArray(),
426+
FinalCardsInHand = _mulliganState?.FinalCardsInHand.Select(x => x.Card.DbfId).ToArray(),
427+
};
428+
}
379429
}
380430
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using HearthDb.CardDefs;
7+
using Entity = Hearthstone_Deck_Tracker.Hearthstone.Entities.Entity;
8+
9+
namespace Hearthstone_Deck_Tracker.Hearthstone
10+
{
11+
internal class MulliganState
12+
{
13+
public List<Entity> OfferedCards { get; private set; } = new List<Entity>();
14+
public List<Entity> KeptCards { get; private set; } = new List<Entity>();
15+
public List<Entity> FinalCardsInHand { get; private set; } = new List<Entity>();
16+
17+
private GameV2 _game;
18+
19+
public MulliganState(GameV2 game)
20+
{
21+
_game = game;
22+
}
23+
24+
public void SnapshotMulligan()
25+
{
26+
OfferedCards = _game.Player.PlayerEntities.Where(x => x.IsInHand && !x.Info.Created).OrderBy(x => x.ZonePosition).ToList();
27+
}
28+
29+
public void SnapshotMulliganChoices(Choice choice)
30+
{
31+
KeptCards = choice.ChosenEntities.ToList();
32+
}
33+
34+
public void SnapshotOpeningHand()
35+
{
36+
FinalCardsInHand = _game.Player.PlayerEntities.Where(x => x.IsInHand && !x.Info.Created).OrderBy(x => x.ZonePosition).ToList();
37+
}
38+
}
39+
}

Hearthstone Deck Tracker/HsReplay/ApiWrapper.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,19 @@ public static async Task UploadLog(LogUploadRequest uploadRequest, string[] logL
209209
return null;
210210
}
211211
}
212+
213+
public static async Task PostMulliganGuideFeedback(MulliganGuideFeedbackParams parameters)
214+
{
215+
try
216+
{
217+
await Client.PostMulliganGuideFeedback(parameters);
218+
}
219+
catch(Exception e)
220+
{
221+
#if(DEBUG)
222+
Log.Error(e);
223+
#endif
224+
}
225+
}
212226
}
213227
}

0 commit comments

Comments
 (0)