diff --git a/README.md b/README.md
index 0ec5c7d..b6d4af0 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,8 @@ device that consumes them, without alt-tabbing or running a sync script.
## Requirements
-- Beat Saber `1.40.8` (PC), via BSIPA.
-- [BeatLeader](https://github.com/BeatLeader/beatleader-mod) `^0.9.0` — must be
+- Beat Saber `1.44.1` (PC), via BSIPA.
+- [BeatLeader](https://github.com/BeatLeader/beatleader-mod) `>=0.9.0` — must be
installed **and signed in** for the sync to authenticate.
- [PlaylistManager](https://github.com/rithik-b/PlaylistManager) `^1.7.0`.
- [BeatSaberPlaylistsLib](https://github.com/Zingabopp/BeatSaberPlaylistsLib)
diff --git a/Setlist/BeatLeaderPlaylistOwnership.cs b/Setlist/BeatLeaderPlaylistOwnership.cs
index 331ad5b..970e0e9 100644
--- a/Setlist/BeatLeaderPlaylistOwnership.cs
+++ b/Setlist/BeatLeaderPlaylistOwnership.cs
@@ -3,8 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using System.Threading;
-using System.Threading.Tasks;
using BeatSaberPlaylistsLib.Types;
using UnityEngine;
using IPALogger = IPA.Logging.Logger;
@@ -20,7 +18,6 @@ namespace Setlist
private const float PlatformUserPollStepSeconds = 0.5f;
/// How long to wait for to appear and populate playerId (plugin runs before menu init).
private const float PlatformUserWaitTimeoutSeconds = 30f;
- private const float PlatformUserGetUserInfoRetrySeconds = 3f;
internal static bool TryExtractBeatLeaderPlaylistGuid(string syncUrl, out string guid)
{
@@ -111,55 +108,18 @@ namespace Setlist
internal static IEnumerator FetchPlatformUserIdCoroutine(Action onDone)
{
var waited = 0f;
- var lastGetUserInfoAttempt = -PlatformUserGetUserInfoRetrySeconds;
while (waited < PlatformUserWaitTimeoutSeconds)
{
foreach (var plm in EnumerateLeaderboardModels())
{
- var pid = plm.playerId;
+ var pid = ReadPlatformUserId(plm);
if (!string.IsNullOrEmpty(pid))
{
- onDone(pid.Trim());
+ onDone(pid);
yield break;
}
}
- if (waited - lastGetUserInfoAttempt >= PlatformUserGetUserInfoRetrySeconds)
- {
- lastGetUserInfoAttempt = waited;
- var model = ResolvePlatformUserModel();
- if (model != null)
- {
- Task task;
- try
- {
- task = model.GetUserInfo(CancellationToken.None);
- }
- catch (Exception)
- {
- task = null;
- }
-
- if (task != null)
- {
- while (!task.IsCompleted)
- {
- yield return null;
- }
-
- if (!task.IsFaulted)
- {
- var uid = task.Result?.platformUserId;
- if (!string.IsNullOrEmpty(uid))
- {
- onDone(uid.Trim());
- yield break;
- }
- }
- }
- }
- }
-
waited += PlatformUserPollStepSeconds;
yield return new WaitForSeconds(PlatformUserPollStepSeconds);
}
@@ -188,26 +148,36 @@ namespace Setlist
}
}
- private static IPlatformUserModel ResolvePlatformUserModel()
+ private static string ReadPlatformUserId(PlatformLeaderboardsModel model)
{
- var field = typeof(PlatformLeaderboardsModel).GetField(
- "_platformUserModel",
- BindingFlags.Instance | BindingFlags.NonPublic);
- if (field == null)
+ if (model == null)
{
return null;
}
- IPlatformUserModel last = null;
- foreach (var plm in EnumerateLeaderboardModels())
+ var id = NormalizeUserId(model.playerId);
+ if (!string.IsNullOrEmpty(id))
{
- if (field.GetValue(plm) is IPlatformUserModel m)
- {
- last = m;
- }
+ return id;
}
- return last;
+ var platformField = typeof(PlatformLeaderboardsModel).GetField(
+ "_platform",
+ BindingFlags.Instance | BindingFlags.NonPublic);
+ var platform = platformField?.GetValue(model);
+ var user = platform?.GetType().GetProperty("user")?.GetValue(platform, null);
+ return NormalizeUserId(user?.GetType().GetProperty("userId")?.GetValue(user, null));
+ }
+
+ private static string NormalizeUserId(object raw)
+ {
+ if (raw == null)
+ {
+ return null;
+ }
+
+ var value = raw.ToString()?.Trim();
+ return string.IsNullOrEmpty(value) || value == "0" ? null : value;
}
///
diff --git a/Setlist/Plugin.cs b/Setlist/Plugin.cs
index baf5cf0..7c0c411 100644
--- a/Setlist/Plugin.cs
+++ b/Setlist/Plugin.cs
@@ -1,8 +1,10 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using BeatSaberPlaylistsLib.Types;
using IPA;
using PlaylistManager.Utilities;
+using UnityEngine;
using IPALogger = IPA.Logging.Logger;
namespace Setlist
@@ -20,6 +22,9 @@ namespace Setlist
/// Set after the ownership scan resolves the platform user id; used when syncing after PlaylistManager adds a song.
internal static string CachedPlatformUserId { get; set; }
+ private const float PlaylistScanPollStepSeconds = 0.5f;
+ private const float PlaylistScanWaitTimeoutSeconds = 10f;
+
[Init]
public Plugin(IPALogger logger)
{
@@ -36,43 +41,55 @@ namespace Setlist
Events.playlistSongAdded += OnPlaylistSongAdded;
+ SetlistSyncHost.Instance.StartPlaylistOwnershipScan(Log);
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ }
+ }
+
+ internal static IEnumerator CoScanAndLogPlaylistOwnership(IPALogger log)
+ {
+ var waited = 0f;
+ while (waited <= PlaylistScanWaitTimeoutSeconds)
+ {
var playlists = BeatSaberPlaylistsLib.PlaylistManager.DefaultManager.GetAllPlaylists(
includeChildren: true,
out AggregateException loadErrors);
if (loadErrors != null)
{
- Log.Error(loadErrors.Message);
+ log.Error(loadErrors.Message);
foreach (var inner in loadErrors.InnerExceptions)
{
- Log.Error(inner.ToString());
+ log.Error(inner.ToString());
}
}
- if (playlists == null || playlists.Length == 0)
+ if (playlists != null && playlists.Length > 0)
{
- Log.Info("No playlists loaded (or playlist library not initialized yet).");
- return;
+ var entries = new List<(IPlaylist Playlist, string Title, bool HasSyncUrl, string BeatLeaderGuid, string OwnerId)>();
+ foreach (var playlist in playlists)
+ {
+ BeatLeaderPlaylistOwnership.TryReadBeatLeaderMetadata(
+ playlist,
+ out var hasSyncUrl,
+ out var blGuid,
+ out var ownerId);
+
+ entries.Add((playlist, playlist.Title, hasSyncUrl, blGuid, ownerId));
+ }
+
+ BeatLeaderPlaylistOwnership.ScheduleVerifyAndLog(entries, log);
+ yield break;
}
- var entries = new List<(IPlaylist Playlist, string Title, bool HasSyncUrl, string BeatLeaderGuid, string OwnerId)>();
- foreach (var playlist in playlists)
- {
- BeatLeaderPlaylistOwnership.TryReadBeatLeaderMetadata(
- playlist,
- out var hasSyncUrl,
- out var blGuid,
- out var ownerId);
-
- entries.Add((playlist, playlist.Title, hasSyncUrl, blGuid, ownerId));
- }
-
- BeatLeaderPlaylistOwnership.ScheduleVerifyAndLog(entries, Log);
- }
- catch (Exception ex)
- {
- Log.Error(ex.ToString());
+ waited += PlaylistScanPollStepSeconds;
+ yield return new WaitForSeconds(PlaylistScanPollStepSeconds);
}
+
+ log.Info("No playlists loaded after startup wait.");
}
[OnExit]
diff --git a/Setlist/Properties/AssemblyInfo.cs b/Setlist/Properties/AssemblyInfo.cs
index e38d79a..51454d5 100644
--- a/Setlist/Properties/AssemblyInfo.cs
+++ b/Setlist/Properties/AssemblyInfo.cs
@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("50F53E6E-21D5-4780-8E67-273877DAA28C")]
-[assembly: AssemblyVersion("0.1.0.0")]
-[assembly: AssemblyFileVersion("0.1.0.0")]
+[assembly: AssemblyVersion("0.1.1.0")]
+[assembly: AssemblyFileVersion("0.1.1.0")]
diff --git a/Setlist/SetlistSyncHost.cs b/Setlist/SetlistSyncHost.cs
index 2a0d866..fb24f8c 100644
--- a/Setlist/SetlistSyncHost.cs
+++ b/Setlist/SetlistSyncHost.cs
@@ -28,5 +28,10 @@ namespace Setlist
{
StartCoroutine(BeatLeaderPlaylistSync.CoPostOwnedPlaylistToBeatLeader(playlist, log));
}
+
+ internal void StartPlaylistOwnershipScan(IPALogger log)
+ {
+ StartCoroutine(Plugin.CoScanAndLogPlaylistOwnership(log));
+ }
}
}
diff --git a/Setlist/manifest.json b/Setlist/manifest.json
index 0e5ed9a..8b2c090 100644
--- a/Setlist/manifest.json
+++ b/Setlist/manifest.json
@@ -3,13 +3,13 @@
"id": "Setlist",
"name": "Setlist",
"author": "",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "Syncs playlists with external sources.",
- "gameVersion": "1.40.8",
+ "gameVersion": "1.44.1",
"dependsOn": {
"BSIPA": "^4.3.0",
"BeatSaberPlaylistsLib": "^1.7.0",
- "BeatLeader": "^0.9.0",
+ "BeatLeader": ">=0.9.0",
"PlaylistManager": "^1.7.0"
}
}
diff --git a/docs/notes.md b/docs/notes.md
index 5a48c8e..25c0819 100644
--- a/docs/notes.md
+++ b/docs/notes.md
@@ -3,13 +3,13 @@
Gamedir
```sh
-cd ~/.local/share/BSManager/BSInstances/1.40.8
+cd ~/.local/share/BSManager/BSInstances/1.44.1
```
## Logs
```sh
-tail -f Logs/_latest.log
+tail -F Logs/_latest.log
```
## FPFC Mode
@@ -23,7 +23,7 @@ Mouse input is broken because Wayland is not yet supported.
To run beat saber, you can mimic the launch execution that bs-manager performs with the following:
```sh
-cd "/home/pleb/.local/share/BSManager/BSInstances/1.40.8"
+cd "/home/pleb/.local/share/BSManager/BSInstances/1.44.1"
export SteamAppId=620980 SteamOverlayGameId=620980 SteamGameId=620980
export WINEDLLOVERRIDES='winhttp=n,b'
@@ -40,7 +40,7 @@ steam-run "/home/pleb/.local/share/Steam/steamapps/common/Proton - Experimental/
Then, after a few seconds you can read the log messages after BS starts up
```
-cat ~/.local/share/BSManager/BSInstances/1.40.8/Logs/_latest.log | grep Setlist
+cat ~/.local/share/BSManager/BSInstances/1.44.1/Logs/_latest.log | grep Setlist
```
Thereafter, kill the process.