Skip to content

Commit aecd75e

Browse files
committed
beatsaver incident
1 parent 15028b0 commit aecd75e

6 files changed

Lines changed: 113 additions & 39 deletions

File tree

BeatSaberCustomCampaigns/Challenge.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using System.Linq;
77
using IPA.Utilities;
88
using UnityEngine;
9+
using UnityEngine.Networking;
10+
using System.Globalization;
911

1012
namespace BeatSaberCustomCampaigns
1113
{
@@ -14,6 +16,7 @@ public class Challenge
1416
{
1517
public string name;
1618
public string songid;
19+
public string hash = "";
1720
public string customDownloadURL = "";
1821
public string characteristic = "Standard";
1922
public BeatmapDifficulty difficulty;
@@ -42,9 +45,20 @@ public CustomPreviewBeatmapLevel FindSong()
4245
{
4346
try
4447
{
45-
CustomPreviewBeatmapLevel level = Loader.CustomLevels.Values.First(x => x.customLevelPath.Contains("\\" + songid + (customDownloadURL == "" ? " " : ""))); //Including the space is to ensure that if they have a map with an old style beatsaver id it won't be falsely detected
48+
CustomPreviewBeatmapLevel level = null;
49+
if (hash != "")
50+
{
51+
var beatmapLevelsModel = Resources.FindObjectsOfTypeAll<BeatmapLevelsModel>().FirstOrDefault(x => x.customLevelPackCollection != null);
52+
level = (CustomPreviewBeatmapLevel) beatmapLevelsModel?.GetLevelPreviewForLevelId("custom_level_" + hash.ToUpper());
53+
return level;
54+
}
55+
56+
// Including the space is to ensure that if they have a map with an old style beatsaver id it won't be falsely detected
57+
string songidSearch = "\\" + songid + (customDownloadURL == "" ? " " : "");
58+
level = Loader.CustomLevels.Values.First(x => CultureInfo.CurrentCulture.CompareInfo.IndexOf(x.customLevelPath, songidSearch, CompareOptions.IgnoreCase) >= 0);
4659
return level;
4760
}
61+
4862
catch
4963
{
5064
return null;
@@ -88,10 +102,7 @@ public MissionDataSO GetMissionData(Campaign campaign)
88102
}
89103
return data;
90104
}
91-
public string GetDownloadURL()
92-
{
93-
return customDownloadURL == "" ? ("https://beatsaver.com/api/download/key/" + songid) : (customDownloadURL);
94-
}
105+
95106
public string GetHash()
96107
{
97108
return APITools.GetHash(rawJSON);

BeatSaberCustomCampaigns/Harmony Patches/MissionLevelDetailViewControllerRefreshContent.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ static bool Prefix(MissionLevelDetailViewController __instance, MissionNode ____
2828
____levelBar.GetPrivateField<TextMeshProUGUI>("_songNameText").text = "SONG NOT FOUND";
2929
____levelBar.GetPrivateField<TextMeshProUGUI>("_difficultyText").text = "SONG NOT FOUND";
3030
____levelBar.GetPrivateField<TextMeshProUGUI>("_authorNameText").text = "SONG NOT FOUND";
31+
____levelBar.GetPrivateField<ImageView>("_songArtworkImageView").sprite = SongCore.Loader.defaultCoverImage;
3132
}
3233
else
3334
{

BeatSaberCustomCampaigns/SongDownloader.cs

Lines changed: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ class SongDownloader : PersistentSingleton<SongDownloader>
1818

1919
private Action onFinish;
2020
private Action onFail;
21+
private Action onGetDownloadURL;
22+
private Action onGetDownloadURLFail;
2123

22-
public void DownloadSong(string songid, string url, bool isBeatSaver, Action onFinish = null, Action onFail = null)
24+
private string beatSaverURL;
25+
private DetailResponse beatSaverResponse;
26+
27+
public void DownloadSong(string songid, string hash, string customDownloadURL, Action onFinish = null, Action onFail = null)
2328
{
29+
bool isBeatSaver = customDownloadURL == "";
2430
if (IsDownloading)
2531
{
2632
onFail?.Invoke();
@@ -29,7 +35,28 @@ public void DownloadSong(string songid, string url, bool isBeatSaver, Action onF
2935
this.onFail = onFail;
3036
this.onFinish = onFinish;
3137
IsDownloading = true;
32-
StartCoroutine(DownloadSongCoroutine(songid, url, isBeatSaver));
38+
39+
if (isBeatSaver)
40+
{
41+
if (hash == "")
42+
{
43+
this.onGetDownloadURL = delegate { StartCoroutine(DownloadSongCoroutine(songid, beatSaverURL, isBeatSaver)); };
44+
this.onGetDownloadURLFail = delegate { onFail?.Invoke(); };
45+
StartCoroutine(GetDownloadUrl(songid));
46+
}
47+
48+
else
49+
{
50+
string url = "https://cdn.beatsaver.com/ " + hash.ToLower() + ".zip";
51+
StartCoroutine(DownloadSongCoroutine(songid, url, isBeatSaver));
52+
}
53+
54+
}
55+
else
56+
{
57+
StartCoroutine(DownloadSongCoroutine(songid, customDownloadURL, isBeatSaver));
58+
}
59+
3360
}
3461

3562
private IEnumerator DownloadSongCoroutine(string songid, string url, bool isBeatSaver)
@@ -66,38 +93,10 @@ private IEnumerator DownloadSongCoroutine(string songid, string url, bool isBeat
6693

6794
byte[] data = www.downloadHandler.data;
6895

69-
7096
string extra = "";
7197
if (isBeatSaver)
7298
{
73-
var www2 = UnityWebRequest.Get("https://beatsaver.com/api/maps/detail/" + songid);
74-
www2.SetRequestHeader("User-Agent", $"CustomCampaigns/v{Plugin.version}");
75-
76-
var timeout2 = false;
77-
var time2 = 0f;
78-
79-
var asyncRequest2 = www2.SendWebRequest();
80-
81-
while (!asyncRequest2.isDone || asyncRequest2.progress < 1f)
82-
{
83-
yield return null;
84-
85-
time2 += Time.deltaTime;
86-
87-
if (!(time2 >= 15f) || asyncRequest2.progress != 0f) continue;
88-
www2.Abort();
89-
timeout2 = true;
90-
}
91-
92-
if (www2.isNetworkError || www2.isHttpError || timeout2)
93-
{
94-
www2.Abort();
95-
}
96-
else
97-
{
98-
DetailResponse response = JsonConvert.DeserializeObject<DetailResponse>(www2.downloadHandler.text);
99-
extra = " (" + response.metadata.songName + " - " + response.metadata.levelAuthorName + ")";
100-
}
99+
extra = " (" + beatSaverResponse.metadata.songName + " - " + beatSaverResponse.metadata.levelAuthorName + ")";
101100
}
102101

103102
Stream zipStream = null;
@@ -123,6 +122,52 @@ private IEnumerator DownloadSongCoroutine(string songid, string url, bool isBeat
123122
Loader.Instance.RefreshSongs();
124123
}
125124
}
125+
126+
private IEnumerator GetDownloadUrl(string songid)
127+
{
128+
string url = "https://api.beatsaver.com/maps/id/" + songid;
129+
var www = UnityWebRequest.Get(url);
130+
www.SetRequestHeader("User-Agent", $"CustomCampaigns/v{Plugin.version}");
131+
132+
var timeout = false;
133+
var time = 0f;
134+
135+
var asyncRequest = www.SendWebRequest();
136+
137+
while (!asyncRequest.isDone || asyncRequest.progress < 1f)
138+
{
139+
yield return null;
140+
141+
time += Time.deltaTime;
142+
143+
if (!(time >= 15f) || asyncRequest.progress != 0f) continue;
144+
www.Abort();
145+
timeout = true;
146+
}
147+
148+
if (www.isNetworkError || www.isHttpError || timeout)
149+
{
150+
www.Abort();
151+
IsDownloading = false;
152+
onGetDownloadURLFail?.Invoke();
153+
}
154+
else
155+
{
156+
DetailResponse response = JsonConvert.DeserializeObject<DetailResponse>(www.downloadHandler.text);
157+
if (response != null && response.versions.Count > 0)
158+
{
159+
this.beatSaverURL = response.versions[0].downloadURL;
160+
this.beatSaverResponse = response;
161+
onGetDownloadURL?.Invoke();
162+
}
163+
else
164+
{
165+
onGetDownloadURLFail?.Invoke();
166+
}
167+
168+
}
169+
}
170+
126171
private async Task ExtractZipAsync(string songid, Stream zipStream, string customSongsPath)
127172
{
128173
try
@@ -147,11 +192,19 @@ private void OnSongsLoaded(Loader songLoader, ConcurrentDictionary<string, Custo
147192
class DetailResponse
148193
{
149194
public DetailMetadata metadata;
195+
public List<MapVersion> versions;
150196
}
197+
151198
class DetailMetadata
152199
{
153200
public string songName;
154201
public string levelAuthorName;
155202
}
203+
204+
class MapVersion
205+
{
206+
public string downloadURL;
207+
public string coverURL;
208+
}
156209
}
157210
}

BeatSaberCustomCampaigns/ViewControllers/CampaignChallengeLeaderboardViewController.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,21 @@ public IEnumerator UpdateLeaderboardsCoroutine()
3737
}
3838
}
3939

40+
public void UpdateAccuracy()
41+
{
42+
CreateAccuracy();
43+
}
44+
4045
private void CreateAccuracy()
4146
{
4247
if (table == null)
4348
{
4449
return;
4550
}
46-
51+
if (lastClicked.FindSong() == null)
52+
{
53+
return;
54+
}
4755
var maxScore = GetMaxScore();
4856
if (maxScore <= 0)
4957
{

BeatSaberCustomCampaigns/campaign/CustomCampaignFlowCoordinator.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,14 @@ public void HandleMissionLevelDetailViewControllerDidPressPlayButtonDownload(Mis
381381

382382
_playButton.SetButtonText("DOWNLOADING...");
383383
_playButton.interactable = false;
384-
SongDownloader.instance.DownloadSong(challenge.songid, challenge.GetDownloadURL(), challenge.customDownloadURL == "", delegate {
384+
SongDownloader.instance.DownloadSong(challenge.songid, challenge.hash, challenge.customDownloadURL, delegate {
385385
isDownloading = false;
386386
_playButton.interactable = true;
387387
foreach (MissionNode node in curCampaignNodes)
388388
{
389389
node.SetField("_missionDataSO", ((CustomMissionDataSO)node.missionData).challenge.GetMissionData(((CustomMissionDataSO)node.missionData).campaign));
390390
}
391+
_campaignChallengeLeaderbaordViewController.UpdateAccuracy();
391392
_missionNodeSelectionManager.GetField<Action<MissionNodeVisualController>, MissionNodeSelectionManager>("didSelectMissionNodeEvent")(downloadingNode.missionNodeVisualController);
392393
}, delegate {
393394
_playButton.interactable = true;

BeatSaberCustomCampaigns/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"gameVersion": "1.16.4",
66
"id": "Custom Campaigns",
77
"name": "Custom Campaigns",
8-
"version": "2.11.0",
8+
"version": "2.12.0",
99
"dependsOn": {
1010
"SongCore": "^3.4.1",
1111
"BeatSaberMarkupLanguage": "^1.5.4",

0 commit comments

Comments
 (0)