Skip to content

Commit 7ffc41f

Browse files
committed
v1.2.9
v1.2.9
1 parent bad1af1 commit 7ffc41f

9 files changed

Lines changed: 326 additions & 87 deletions

File tree

HDT_BGrank/BGrank.cs

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
using System;
22
using System.IO;
33
using System.Linq;
4+
using System.Threading;
45
using System.Net.Http;
56
using System.Threading.Tasks;
67
using System.Collections.Generic;
78
using HearthMirror;
89
using Hearthstone_Deck_Tracker;
910
using Hearthstone_Deck_Tracker.Enums;
10-
using Hearthstone_Deck_Tracker.Utility.Logging;
1111

1212
namespace HDT_BGrank
1313
{
@@ -21,7 +21,10 @@ public class BGrank
2121
private bool namesReady = false;
2222
private bool playersReady = false;
2323
private bool leaderBoardReady = false;
24+
private int leaderBoardRequested = 0;
25+
private int nameErrors = 0;
2426

27+
private readonly Mirror mirror;
2528
private readonly HttpClient client;
2629
private List<string> oppNames = null;
2730
private Dictionary<string, string> leaderBoard = null;
@@ -30,6 +33,8 @@ public BGrank()
3033
{
3134
client = new HttpClient();
3235
client.DefaultRequestHeaders.Add("User-Agent", "User-Agent-Here");
36+
client.Timeout = TimeSpan.FromSeconds(10);
37+
mirror = new Mirror { ImageName = "Hearthstone" };
3338
}
3439

3540
private void Reset()
@@ -39,6 +44,8 @@ private void Reset()
3944
playersReady = false;
4045
failToGetData = false;
4146
leaderBoardReady = false;
47+
leaderBoardRequested = 0;
48+
nameErrors = 0;
4249
ClearMemory();
4350
}
4451

@@ -47,16 +54,17 @@ public void ClearMemory()
4754
oppDict = null;
4855
oppNames = null;
4956
leaderBoard = null;
57+
mirror.Clean();
5058
}
5159

5260
public void OnGameStart()
5361
{
54-
GetLeaderBoard();
62+
_ = GetLeaderBoard();
5563
}
5664

5765
public void OnTurnStart(ActivePlayer player)
5866
{
59-
GetLeaderBoard();
67+
_ = GetLeaderBoard();
6068
playersReady = true;
6169
}
6270

@@ -77,13 +85,21 @@ public void OnUpdate()
7785
else if (!namesReady) { GetOppNames(); }
7886
else if (leaderBoardReady)
7987
{
80-
Dictionary<string, int> unsortDict = new Dictionary<string, int>();
81-
oppDict = new Dictionary<string, string>();
88+
Dictionary<string, int> unsortDict = new Dictionary<string, int>(oppNames?.Count ?? 0);
89+
oppDict = new Dictionary<string, string>(oppNames?.Count ?? 0);
8290
foreach (string name in oppNames)
8391
{
8492
if (leaderBoard.TryGetValue(name, out string value))
8593
{
86-
unsortDict.Add(name, int.Parse(value));
94+
if (int.TryParse(value, out int rate))
95+
{
96+
unsortDict.Add(name, rate);
97+
}
98+
else
99+
{
100+
FileLogger.Instance.Warn($"Parse MMR failed (unexpected), set MMR as 0. player:'{name}' MMR:'{value}'");
101+
unsortDict.Add(name, 0);
102+
}
87103
}
88104
else
89105
{
@@ -117,6 +133,8 @@ private async Task GetLeaderBoard()
117133
{
118134
if (!Core.Game.IsBattlegroundsMatch || leaderBoardReady || failToGetData) { return; }
119135

136+
if (Interlocked.CompareExchange(ref leaderBoardRequested, 1, 0) != 0) { return; }
137+
120138
// Get the leaderboard information from web, see https://github.com/IBM5100o/BGrank_bot
121139
leaderBoard = new Dictionary<string, string>();
122140
string region = GetRegionStr();
@@ -126,12 +144,12 @@ private async Task GetLeaderBoard()
126144

127145
if (Core.Game.IsBattlegroundsSoloMatch)
128146
{
129-
path = Path.Combine(Config.AppDataPath, $"LeaderBoard_{region}.txt");
147+
path = Path.Combine(Config.AppDataPath, "BGrank", $"LeaderBoard_{region}.txt");
130148
url = $"https://bgrank.fly.dev/{region}/";
131149
}
132150
else
133151
{
134-
path = Path.Combine(Config.AppDataPath, $"LeaderBoard_{region}_duo.txt");
152+
path = Path.Combine(Config.AppDataPath, "BGrank", $"LeaderBoard_{region}_duo.txt");
135153
url = $"https://bgrank.fly.dev/{region}_duo/";
136154
}
137155

@@ -140,11 +158,11 @@ private async Task GetLeaderBoard()
140158
num_tries++;
141159
try
142160
{
143-
Log.Info($"Try to get the leaderboard from {url} (try {num_tries}/{max_tries})");
144-
string response = await client.GetStringAsync(url);
145-
if (string.IsNullOrEmpty(response))
161+
FileLogger.Instance.Info($"Try to get the leaderboard from {url} (try {num_tries}/{max_tries})");
162+
string response = await client.GetStringAsync(url).ConfigureAwait(false);
163+
if (string.IsNullOrWhiteSpace(response))
146164
{
147-
if (num_tries < max_tries) { await Task.Delay(10000); }
165+
if (num_tries < max_tries) { await Task.Delay(5000); }
148166
continue;
149167
}
150168

@@ -157,34 +175,43 @@ private async Task GetLeaderBoard()
157175
{
158176
string name = tmp[0];
159177
string rating = tmp[1];
160-
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(rating)) { continue; }
178+
if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(rating)) { continue; }
161179
if (!leaderBoard.ContainsKey(name)) { leaderBoard.Add(name, rating); }
162180
}
163181
}
164-
165-
if (leaderBoard.Count != 0)
182+
if (leaderBoard.Count != 0)
166183
{
167-
Log.Info("Success to get the leaderboard from web!");
184+
FileLogger.Instance.Info($"Success to get the leaderboard from {url}");
168185
leaderBoardReady = true;
169-
using (StreamWriter writer = new StreamWriter(path))
186+
}
187+
}
188+
catch (Exception ex)
189+
{
190+
FileLogger.Instance.Error($"Failed to get the leaderboard from {url}", ex);
191+
if (num_tries < max_tries) { await Task.Delay(5000); }
192+
}
193+
}
194+
195+
if (leaderBoardReady)
196+
{
197+
try
198+
{
199+
using (StreamWriter writer = new StreamWriter(path))
200+
{
201+
foreach (var player in leaderBoard)
170202
{
171-
foreach (var player in leaderBoard)
172-
{
173-
writer.WriteLine($"{player.Key} {player.Value}");
174-
}
203+
writer.WriteLine($"{player.Key} {player.Value}");
175204
}
176205
}
177206
}
178207
catch (Exception ex)
179208
{
180-
Log.Error(ex);
181-
if (num_tries < max_tries) { await Task.Delay(10000); }
209+
FileLogger.Instance.Error("Failed to save the leaderboard to local", ex);
182210
}
183211
}
184-
185-
if (!leaderBoardReady)
212+
else
186213
{
187-
Log.Info("Fail to get the leaderboard from web, try to get it from local...");
214+
FileLogger.Instance.Info("Failed to get the leaderboard from web, try to get it from local...");
188215
if (File.Exists(path))
189216
{
190217
try
@@ -198,25 +225,26 @@ private async Task GetLeaderBoard()
198225
leaderBoard.Add(tmp[0], tmp[1]);
199226
}
200227
}
201-
if (leaderBoard.Count != 0)
228+
if (leaderBoard.Count != 0)
202229
{
203-
Log.Info("Success to get the leaderboard from local!");
230+
FileLogger.Instance.Info("Success to get the leaderboard from local!");
204231
leaderBoardReady = true;
205232
}
206233
else { failToGetData = true; }
207234
}
208235
catch (Exception ex)
209236
{
210-
Log.Error(ex);
237+
FileLogger.Instance.Error("Failed to read the local file", ex);
211238
failToGetData = true;
212239
}
213240
}
214241
else
215242
{
243+
FileLogger.Instance.Info("Local file not exist");
216244
failToGetData = true;
217245
}
218246
}
219-
if (failToGetData) { Log.Info("Fail to get the leaderboard from local, no data for this match"); }
247+
if (failToGetData) { FileLogger.Instance.Info("Failed to get the leaderboard, no data for this match"); }
220248
}
221249

222250
private string GetRegionStr()
@@ -242,21 +270,20 @@ private void GetOppNames()
242270
try
243271
{
244272
string myName = Reflection.Client?.GetBattleTag()?.Name;
245-
if (string.IsNullOrEmpty(myName)) { return; }
246-
Mirror mirror = new Mirror { ImageName = "Hearthstone" };
273+
if (string.IsNullOrWhiteSpace(myName)) { return; }
247274
var leaderboardMgr = mirror.Root?["PlayerLeaderboardManager"]?["s_instance"];
248275
if (leaderboardMgr == null) { return; }
249276
dynamic[] playerTiles = GetPlayerTiles(leaderboardMgr);
250-
var numberOfPlayerTiles = playerTiles?.Length ?? 0;
277+
int numberOfPlayerTiles = playerTiles?.Length ?? 0;
251278
if (numberOfPlayerTiles == 0) { return; }
252-
List<string> tmpNames = new List<string>();
279+
List<string> tmpNames = new List<string>(numberOfPlayerTiles);
253280

254281
for (int i = 0; i < numberOfPlayerTiles; i++)
255282
{
256283
var playerTile = playerTiles[i];
257284
// Info not available until the player mouses over the tile in the leaderboard, and there is no other way to get it
258285
string playerName = playerTile["m_overlay"]?["m_heroActor"]?["m_playerNameText"]?["m_Text"];
259-
if (string.IsNullOrEmpty(playerName)) { return; }
286+
if (string.IsNullOrWhiteSpace(playerName)) { return; }
260287
if (playerName != myName && !tmpNames.Contains(playerName)) { tmpNames.Add(playerName); }
261288
}
262289

@@ -272,9 +299,17 @@ private void GetOppNames()
272299
oppNames = new List<string>(tmpNames);
273300
namesReady = true;
274301
}
275-
catch (Exception ex)
302+
catch (Exception ex)
276303
{
277-
Log.Error(ex);
304+
nameErrors++;
305+
if (nameErrors < 5)
306+
{
307+
FileLogger.Instance.Error("Fail to get opponent name", ex);
308+
}
309+
else if (nameErrors == 5)
310+
{
311+
FileLogger.Instance.Error("Fail to get opponent name, further errors will be suppressed", ex);
312+
}
278313
}
279314
}
280315

HDT_BGrank/BGrankPlugin.cs

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,34 @@ public string Name
3434

3535
public void OnButtonPress()
3636
{
37+
RemoveComponents();
38+
3739
Settings.Instance.scaleRatio = 1.0;
3840
Settings.Instance.positionLeft = 0.0;
3941
Settings.Instance.positionTop = 0.0;
4042
Settings.Instance.ifLoad = false;
4143
Settings.Save();
4244

43-
if (rank != null)
44-
{
45-
rank = null;
46-
Core.OverlayCanvas.Children.Remove(leaderBoardPanel);
47-
leaderBoardPanel = null;
48-
49-
rank = new BGrank();
50-
GameEvents.OnGameStart.Add(rank.OnGameStart);
51-
GameEvents.OnTurnStart.Add(rank.OnTurnStart);
52-
leaderBoardPanel = new LeaderBoardPanel();
53-
Core.OverlayCanvas.Children.Add(leaderBoardPanel);
54-
leaderBoardPanel.SetHitTestVisible();
55-
}
45+
CreateComponents();
5646
}
5747

5848
public void OnLoad()
5949
{
50+
FileLogger.Initialize(LogLevel.Info, 5);
6051
CreateMenuItem();
6152
MenuItem.IsChecked = true;
6253
}
6354

6455
public void OnUnload()
6556
{
57+
try { FileLogger.Instance.Dispose(); }
58+
catch { /* ignore Dispose errors */ }
6659
MenuItem.IsChecked = false;
6760
}
6861

6962
public void OnUpdate()
7063
{
71-
if (rank != null)
64+
if (rank != null && leaderBoardPanel != null)
7265
{
7366
if ((DateTime.Now - lastUpdate).TotalSeconds >= 1)
7467
{
@@ -90,32 +83,49 @@ private void CreateMenuItem()
9083

9184
MenuItem.Checked += (sender, args) =>
9285
{
93-
if (rank == null)
94-
{
95-
rank = new BGrank();
96-
GameEvents.OnGameStart.Add(rank.OnGameStart);
97-
GameEvents.OnTurnStart.Add(rank.OnTurnStart);
98-
leaderBoardPanel = new LeaderBoardPanel();
99-
Core.OverlayCanvas.Children.Add(leaderBoardPanel);
100-
leaderBoardPanel.SetHitTestVisible();
101-
}
86+
CreateComponents();
10287
};
10388

10489
MenuItem.Unchecked += (sender, args) =>
10590
{
106-
if (rank != null)
107-
{
108-
rank = null;
109-
leaderBoardPanel.SaveSettings();
110-
Core.OverlayCanvas.Children.Remove(leaderBoardPanel);
111-
leaderBoardPanel = null;
112-
}
91+
RemoveComponents();
11392
};
11493
}
11594

95+
private void CreateComponents()
96+
{
97+
if (rank == null)
98+
{
99+
rank = new BGrank();
100+
GameEvents.OnGameStart.Add(rank.OnGameStart);
101+
GameEvents.OnTurnStart.Add(rank.OnTurnStart);
102+
}
103+
if (leaderBoardPanel == null)
104+
{
105+
leaderBoardPanel = new LeaderBoardPanel();
106+
Core.OverlayCanvas.Children.Add(leaderBoardPanel);
107+
leaderBoardPanel.SetHitTestVisible();
108+
}
109+
}
110+
111+
private void RemoveComponents()
112+
{
113+
if (rank != null)
114+
{
115+
rank.ClearMemory();
116+
rank = null;
117+
}
118+
if (leaderBoardPanel != null)
119+
{
120+
leaderBoardPanel.SaveSettings();
121+
Core.OverlayCanvas.Children.Remove(leaderBoardPanel);
122+
leaderBoardPanel = null;
123+
}
124+
}
125+
116126
public Version Version
117127
{
118-
get { return new Version(1, 2, 8); }
128+
get { return new Version(1, 2, 9); }
119129
}
120130

121131
}

0 commit comments

Comments
 (0)