Skip to content

Commit 07d52e5

Browse files
authored
Merge pull request #192 from BeatLeader/br-semaphores-fix
Fixed semaphores not being released because of incorrect handling.
2 parents a3f1f17 + 164fb36 commit 07d52e5

4 files changed

Lines changed: 50 additions & 34 deletions

File tree

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using System.Net.Http;
2+
using System.Threading;
23
using BeatLeader.Models;
34
using BeatLeader.Utils;
45
using BeatLeader.WebRequests;
56

67
namespace BeatLeader.API {
78
internal class GetAvatarRequest : PersistentWebRequestBase<AvatarSettings, JsonResponseParser<AvatarSettings>> {
8-
public static IWebRequest<AvatarSettings> Send(string playerId) {
9-
return SendRet($"{BLConstants.BEATLEADER_API_URL}/player/{playerId}/ingameavatar", HttpMethod.Get);
9+
public static IWebRequest<AvatarSettings> Send(string playerId, CancellationToken token = default) {
10+
return SendRet($"{BLConstants.BEATLEADER_API_URL}/player/{playerId}/ingameavatar", HttpMethod.Get, token: token);
1011
}
1112
}
1213
}

Source/2_Core/Models/API/BeatLeader/Player.cs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
using Newtonsoft.Json;
77
using BeatLeader.Themes;
88
using BeatLeader.Utils;
9+
using BeatLeader.WebRequests;
910
using BeatSaber.BeatAvatarSDK;
11+
using UnityEngine;
1012

1113
namespace BeatLeader.Models {
1214
public class PlayerContextExtension {
@@ -32,20 +34,30 @@ public class Player : IPlayer {
3234
float IPlayer.PerformancePoints => pp;
3335
IPlayerProfileSettings? IPlayer.ProfileSettings => profileSettings;
3436

35-
private static readonly Dictionary<string, AvatarSettings?> avatarSettingsCache = new();
37+
private static readonly Dictionary<string, AvatarSettings> avatarSettingsCache = new();
3638
private static readonly Dictionary<string, SemaphoreSlim?> semaphores = new();
3739

3840
public async Task<AvatarData> GetBeatAvatarAsync(bool bypassCache, CancellationToken token) {
39-
var semaphore = semaphores.GetOrAdd(id, new SemaphoreSlim(1, 1))!;
40-
await semaphore.WaitAsync(token);
41-
42-
if (!avatarSettingsCache.TryGetValue(id, out var avatarSettings) || bypassCache) {
43-
var request = await GetAvatarRequest.Send(id).Join();
44-
avatarSettings = request.Result;
45-
avatarSettingsCache[id] = avatarSettings;
41+
if (!semaphores.TryGetValue(id, out var semaphore)) {
42+
semaphore = new(1, 1);
43+
semaphores[id] = semaphore;
4644
}
4745

48-
semaphore.Release();
46+
await semaphore!.WaitAsync(token);
47+
48+
AvatarSettings avatarSettings;
49+
try {
50+
if (!avatarSettingsCache.TryGetValue(id, out avatarSettings) || bypassCache) {
51+
var request = await GetAvatarRequest.Send(id, token).Join();
52+
53+
if (request.Result != null) {
54+
avatarSettings = request.Result!;
55+
avatarSettingsCache[id] = avatarSettings;
56+
}
57+
}
58+
} finally {
59+
semaphore.Release();
60+
}
4961

5062
return avatarSettings?.ToAvatarData() ?? AvatarUtils.DefaultAvatarData;
5163
}
@@ -138,11 +150,9 @@ private float? Saturation {
138150
set => saturation = value ?? 0;
139151
}
140152

141-
[JsonIgnore]
142-
public int hue;
153+
[JsonIgnore] public int hue;
143154

144-
[JsonIgnore]
145-
public float saturation;
155+
[JsonIgnore] public float saturation;
146156

147157
public string message;
148158

Source/8_UI/FlowCoordinator/Flows/BattleRoyaleFlow/Views/OpponentsView/BattleRoyaleOpponentsList.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ protected override void OnUpdate() {
137137
_valueAnimator.SetTarget(1f);
138138
}
139139
}
140-
//
140+
141141
var targetColor = _colorShouldBeSet ? _targetColor : Color.white.ColorWithAlpha(0.3f);
142142
var color = Color.Lerp(
143143
Color.white.ColorWithAlpha(0.1f),
@@ -178,16 +178,18 @@ protected override void OnInit(BattleRoyaleReplay item) {
178178
return;
179179
}
180180

181-
if (_refreshColorTask?.Status is TaskStatus.Running || _refreshPlayerTask?.Status is TaskStatus.Running) {
181+
if (_refreshColorTask != null || _refreshPlayerTask != null) {
182182
_tokenSource.Cancel();
183183
_tokenSource = new();
184184
}
185185

186186
ResetColor();
187187
RefreshOtherText();
188188

189-
_refreshPlayerTask = RefreshPlayer(_tokenSource.Token).RunCatching();
190-
_refreshColorTask = RefreshAccentColor(_tokenSource.Token).RunCatching();
189+
var token = _tokenSource.Token;
190+
191+
_refreshPlayerTask = RefreshPlayer(item, token).RunCatching();
192+
_refreshColorTask = RefreshAccentColor(item, token).RunCatching();
191193

192194
_prevReplay = item;
193195
_prevRank = item.ReplayRank;
@@ -199,27 +201,28 @@ public void Init(IBattleRoyaleHost battleRoyaleHost) {
199201
_navigateButton.Enabled = battleRoyaleHost.CanMutateLobby;
200202
}
201203

202-
private async Task RefreshAccentColor(CancellationToken token) {
203-
var data = await Item.GetBattleRoyaleDataAsync(false, token);
204+
private async Task RefreshAccentColor(BattleRoyaleReplay replay, CancellationToken token) {
205+
var data = await replay.GetBattleRoyaleDataAsync(false, token);
204206

205207
if (token.IsCancellationRequested) {
206208
return;
207209
}
208210

209211
var color = data.AccentColor ?? Color.white;
210212
SetColor(color);
213+
_refreshColorTask = null;
211214
}
212215

213-
private async Task RefreshPlayer(CancellationToken token) {
214-
var header = Item.ReplayHeader;
215-
var player = await header.LoadPlayerAsync(false, token) as IPlayer;
216+
private async Task RefreshPlayer(BattleRoyaleReplay replay, CancellationToken token) {
217+
var player = await replay.ReplayHeader.LoadPlayerAsync(false, token) as IPlayer;
216218

217219
if (token.IsCancellationRequested) {
218220
return;
219221
}
220222

221223
_playerAvatar.SetAvatar(player);
222224
_playerNameText.Text = player.Name;
225+
_refreshPlayerTask = null;
223226
}
224227

225228
private void RefreshOtherText() {
@@ -256,15 +259,15 @@ public void Setup(IBattleRoyaleHost? battleRoyaleHost) {
256259
_battleRoyaleHost.ReplayRefreshRequestedEvent -= HandleRefreshRequested;
257260
_battleRoyaleHost.CanMutateLobbyStateChangedEvent -= HandleCanMutateLobbyChangedEvent;
258261
}
259-
262+
260263
_battleRoyaleHost = battleRoyaleHost;
261-
264+
262265
if (_battleRoyaleHost != null) {
263266
_battleRoyaleHost.ReplayAddedEvent += HandleReplayAdded;
264267
_battleRoyaleHost.ReplayRemovedEvent += HandleReplayRemoved;
265268
_battleRoyaleHost.ReplayRefreshRequestedEvent += HandleRefreshRequested;
266269
_battleRoyaleHost.CanMutateLobbyStateChangedEvent += HandleCanMutateLobbyChangedEvent;
267-
270+
268271
HandleCanMutateLobbyChangedEvent(_battleRoyaleHost.CanMutateLobby);
269272
}
270273
}

Source/8_UI/Models/FlowCoordinator/BattleRoyale/BattleRoyaleReplay.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@ public BattleRoyaleReplay(IReplayHeader header) {
2121
public async Task<BattleRoyaleReplayData> GetBattleRoyaleDataAsync(bool bypassCache, CancellationToken token) {
2222
if (_replayData == null || bypassCache) {
2323
await _semaphoreSlim.WaitAsync(token);
24-
25-
var player = await ReplayHeader.LoadPlayerAsync(false, token);
26-
var avatarData = await player.GetBeatAvatarAsync(false, token);
2724

28-
var info = ReplayHeader.ReplayInfo;
29-
var accentColor = GetReplayColor(info);
25+
try {
26+
var player = await ReplayHeader.LoadPlayerAsync(false, token);
27+
var avatarData = await player.GetBeatAvatarAsync(false, token);
3028

31-
_replayData = new BattleRoyaleReplayData(avatarData, accentColor);
29+
var info = ReplayHeader.ReplayInfo;
30+
var accentColor = GetReplayColor(info);
3231

33-
_semaphoreSlim.Release();
32+
_replayData = new BattleRoyaleReplayData(avatarData, accentColor);
33+
} finally {
34+
_semaphoreSlim.Release();
35+
}
3436
}
3537

3638
return _replayData.Value;

0 commit comments

Comments
 (0)