diff --git a/Facepunch.Steamworks.Test/Client/FriendsTest.cs b/Facepunch.Steamworks.Test/Client/FriendsTest.cs
index bcaf8a4..3efe14e 100644
--- a/Facepunch.Steamworks.Test/Client/FriendsTest.cs
+++ b/Facepunch.Steamworks.Test/Client/FriendsTest.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
@@ -98,6 +99,35 @@ public void CachedAvatar()
}
}
+ [TestMethod]
+ public void FetchUsername()
+ {
+ using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
+ {
+ Assert.IsTrue(client.IsValid);
+
+ const ulong id = 76561198095600584u;
+
+ var passed = false;
+ var timeout = TimeSpan.FromSeconds(10d);
+
+ client.Friends.GetName( id, name =>
+ {
+ Console.WriteLine( name );
+ passed = true;
+ } );
+
+ while ( !passed && timeout > TimeSpan.Zero )
+ {
+ client.Update();
+ System.Threading.Thread.Sleep( 10 );
+ timeout -= TimeSpan.FromMilliseconds( 10 );
+ }
+
+ Assert.IsTrue( passed );
+ }
+ }
+
public static void DrawImage( Image img )
{
var grad = " -:+#";
diff --git a/Facepunch.Steamworks.Test/Client/LeaderboardTest.cs b/Facepunch.Steamworks.Test/Client/LeaderboardTest.cs
index 3628d11..ea1d8a8 100644
--- a/Facepunch.Steamworks.Test/Client/LeaderboardTest.cs
+++ b/Facepunch.Steamworks.Test/Client/LeaderboardTest.cs
@@ -58,7 +58,7 @@ public void GetLeaderboard()
foreach ( var entry in board.Results )
{
- Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({entry.Name}) with {entry.Score}" );
+ Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({client.Friends.GetCachedName(entry.SteamId)}) with {entry.Score}" );
if ( entry.SubScores != null )
Console.WriteLine( " - " + string.Join( ";", entry.SubScores.Select( x => x.ToString() ).ToArray() ) );
@@ -97,7 +97,7 @@ public void GetLeaderboardCallback()
{
foreach ( var entry in results )
{
- Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({entry.Name}) with {entry.Score}" );
+ Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({client.Friends.GetCachedName(entry.SteamId)}) with {entry.Score}" );
if ( entry.SubScores != null )
Console.WriteLine( " - " + string.Join( ";", entry.SubScores.Select( x => x.ToString() ).ToArray() ) );
diff --git a/Facepunch.Steamworks.Test/Client/LobbyTest.cs b/Facepunch.Steamworks.Test/Client/LobbyTest.cs
index 17241a3..ee36c82 100644
--- a/Facepunch.Steamworks.Test/Client/LobbyTest.cs
+++ b/Facepunch.Steamworks.Test/Client/LobbyTest.cs
@@ -365,7 +365,7 @@ public void SetGetUserMetadata()
client.Lobby.OnLobbyMemberDataUpdated = (steamID) =>
{
- string name = client.Friends.GetName(steamID);
+ string name = client.Friends.GetCachedName(steamID);
Console.WriteLine(name + " updated data");
Assert.IsTrue(client.Lobby.GetMemberData(steamID, "testkey") == "testvalue");
Console.WriteLine("testkey is now: " + client.Lobby.GetMemberData(steamID, "testkey"));
diff --git a/Facepunch.Steamworks/Client/Friends.cs b/Facepunch.Steamworks/Client/Friends.cs
index 9b09bf7..ad17ca9 100644
--- a/Facepunch.Steamworks/Client/Friends.cs
+++ b/Facepunch.Steamworks/Client/Friends.cs
@@ -121,13 +121,12 @@ public bool UpdateInformation( ulong steamid )
{
return !client.native.friends.RequestUserInformation( steamid, false );
}
-
+
///
- /// Get this user's name
+ /// Get this user's name immediately. This should work for people on your friends list.
///
- public string GetName( ulong steamid )
+ public string GetCachedName( ulong steamid )
{
- client.native.friends.RequestUserInformation( steamid, true );
return client.native.friends.GetFriendPersonaName( steamid );
}
@@ -270,7 +269,7 @@ public void GetAvatar( AvatarSize size, ulong steamid, Action callback )
}
// Lets request it from Steam
- if (!client.native.friends.RequestUserInformation(steamid, false))
+ if ( !client.native.friends.RequestUserInformation( steamid, false ) )
{
// from docs: false means that we already have all the details about that user, and functions that require this information can be used immediately
// but that's probably not true because we just checked the cache
@@ -287,7 +286,7 @@ public void GetAvatar( AvatarSize size, ulong steamid, Action callback )
// if not it'll time out anyway
}
- PersonaCallbacks.Add( new PersonaCallback
+ AvatarCallbacks.Add( new PersonaCallback
{
SteamId = steamid,
Size = size,
@@ -296,15 +295,54 @@ public void GetAvatar( AvatarSize size, ulong steamid, Action callback )
});
}
- private class PersonaCallback
+ public const string DefaultName = "[unknown]";
+
+ public void GetName( ulong steamid, Action callback )
+ {
+ // Maybe we already have it downloaded?
+ var name = GetCachedName( steamid );
+ if ( name != null && name != DefaultName )
+ {
+ callback( name );
+ return;
+ }
+
+ // Lets request it from Steam
+ if ( !client.native.friends.RequestUserInformation( steamid, true ) )
+ {
+ // from docs: false means that we already have all the details about that user, and functions that require this information can be used immediately
+ // but that's probably not true because we just checked the cache
+
+ // check again in case it was just a race
+ name = GetCachedName( steamid );
+ if ( name != null && name != DefaultName )
+ {
+ callback( name );
+ return;
+ }
+
+ // maybe Steam returns false if it was already requested? just add another callback and hope it comes
+ // if not it'll time out anyway
+ }
+
+ NameCallbacks.Add( new PersonaCallback
+ {
+ SteamId = steamid,
+ Callback = callback,
+ Time = DateTime.Now
+ } );
+ }
+
+ private class PersonaCallback
{
public ulong SteamId;
public AvatarSize Size;
- public Action Callback;
+ public Action Callback;
public DateTime Time;
}
- List PersonaCallbacks = new List();
+ List> AvatarCallbacks = new List>();
+ List> NameCallbacks = new List>();
public SteamFriend Get( ulong steamid )
{
@@ -324,121 +362,50 @@ public SteamFriend Get( ulong steamid )
internal void Cycle()
{
- if ( PersonaCallbacks.Count == 0 ) return;
+ CycleCallbacks( AvatarCallbacks, callback => GetCachedAvatar( callback.Size, callback.SteamId ) );
+ CycleCallbacks( NameCallbacks, callback => GetCachedName( callback.SteamId ) );
+ }
+
+ private void CycleCallbacks( List> callbacks, Func, T> getter )
+ {
+ if ( callbacks.Count == 0 ) return;
var timeOut = DateTime.Now.AddSeconds( -10 );
- for ( int i = PersonaCallbacks.Count-1; i >= 0; i-- )
+ for ( int i = callbacks.Count-1; i >= 0; i-- )
{
- var cb = PersonaCallbacks[i];
+ var cb = callbacks[i];
// Timeout
- if ( cb.Time < timeOut )
+ if ( cb.Time >= timeOut ) continue;
+
+ if ( cb.Callback != null )
{
- if ( cb.Callback != null )
- {
- // final attempt, will be null unless the callback was missed somehow
- var image = GetCachedAvatar( cb.Size, cb.SteamId );
+ // final attempt, will be null unless the callback was missed somehow
+ var image = getter( cb );
- cb.Callback( image );
- }
-
- PersonaCallbacks.Remove( cb );
- continue;
+ cb.Callback( image );
}
+
+ callbacks.Remove( cb );
}
}
- public delegate void FetchInformationCallback(ulong steamid);
-
private const int PersonaChangeName = 0x0001;
private const int PersonaChangeAvatar = 0x0040;
- private readonly Dictionary> _fetchInformationRequests =
- new Dictionary>();
- private static readonly List> _tempCallbackList
- = new List>();
-
- public void FetchUserInformation( ulong steamid, bool nameOnly, FetchInformationCallback callback )
- {
- if ( callback == null ) throw new ArgumentNullException( nameof(callback) );
-
- if ( !client.native.friends.RequestUserInformation( steamid, nameOnly ) )
- {
- // Already got this user's info
- callback( steamid );
- return;
- }
-
- var flags = PersonaChangeName | (nameOnly ? 0 : PersonaChangeAvatar);
-
- if ( !_fetchInformationRequests.TryGetValue( steamid, out var outer) )
- {
- outer = new Dictionary();
- _fetchInformationRequests.Add( steamid, outer );
- }
-
- FetchInformationCallback inner;
- if ( !outer.TryGetValue( flags, out inner ) )
- {
- outer.Add( flags, callback );
- return;
- }
-
- outer[flags] = inner + callback;
- }
-
private void OnPersonaStateChange( PersonaStateChange_t data )
{
- // k_EPersonaChangeAvatar
+ if ( (data.ChangeFlags & PersonaChangeName) != 0 )
+ {
+ LoadNameForSteamId( data.SteamID );
+ }
+
if ( (data.ChangeFlags & PersonaChangeAvatar) != 0 )
{
LoadAvatarForSteamId( data.SteamID );
}
- if ( _fetchInformationRequests.TryGetValue( data.SteamID, out var outer ) )
- {
- var list = _tempCallbackList;
-
- list.Clear();
-
- foreach ( var pair in outer )
- {
- list.Add(pair);
- }
-
- foreach ( var pair in list )
- {
- var flags = pair.Key & data.ChangeFlags;
- if ( flags == 0 )
- {
- // No new information for this request
- continue;
- }
-
- outer.Remove( pair.Key );
-
- if ( flags == pair.Key )
- {
- // All requested information has been provided
- pair.Value( data.SteamID );
- continue;
- }
-
- // Still missing some information
- var remainingFlags = pair.Key ^ flags;
-
- if ( outer.TryGetValue( remainingFlags, out var existing ) )
- {
- outer[remainingFlags] = existing + pair.Value;
- }
- else
- {
- outer.Add( remainingFlags, pair.Value );
- }
- }
- }
-
//
// Find and refresh this friend's status
//
@@ -452,20 +419,33 @@ private void OnPersonaStateChange( PersonaStateChange_t data )
void LoadAvatarForSteamId( ulong Steamid )
{
- for ( int i = PersonaCallbacks.Count - 1; i >= 0; i-- )
+ for ( int i = AvatarCallbacks.Count - 1; i >= 0; i-- )
{
- var cb = PersonaCallbacks[i];
+ var cb = AvatarCallbacks[i];
if ( cb.SteamId != Steamid ) continue;
var image = GetCachedAvatar( cb.Size, cb.SteamId );
if ( image == null ) continue;
- PersonaCallbacks.Remove( cb );
+ AvatarCallbacks.Remove( cb );
- if ( cb.Callback != null )
- {
- cb.Callback( image );
- }
+ cb.Callback?.Invoke( image );
+ }
+ }
+
+ void LoadNameForSteamId( ulong Steamid )
+ {
+ for ( int i = NameCallbacks.Count - 1; i >= 0; i-- )
+ {
+ var cb = NameCallbacks[i];
+ if ( cb.SteamId != Steamid ) continue;
+
+ var name = GetCachedName( cb.SteamId );
+ if ( name == null ) continue;
+
+ NameCallbacks.Remove( cb );
+
+ cb.Callback?.Invoke( name );
}
}
diff --git a/Facepunch.Steamworks/Client/Leaderboard.cs b/Facepunch.Steamworks/Client/Leaderboard.cs
index c338906..bbdcc2a 100644
--- a/Facepunch.Steamworks/Client/Leaderboard.cs
+++ b/Facepunch.Steamworks/Client/Leaderboard.cs
@@ -283,7 +283,6 @@ private unsafe void ReadScores( LeaderboardScoresDownloaded_t result, List> 32) == 0xffffffff ? null : new RemoteFile( client.RemoteStorage, entry.UGC )
} );
}
@@ -379,12 +378,6 @@ public struct Entry
public int[] SubScores;
public int GlobalRank;
public RemoteFile AttachedFile;
-
- ///
- /// Note that the player's name might not be immediately available.
- /// If that's the case you'll have to use Friends.GetName to find the name
- ///
- public string Name;
}
}
}
diff --git a/Facepunch.Steamworks/Interfaces/Workshop.Item.cs b/Facepunch.Steamworks/Interfaces/Workshop.Item.cs
index 615b38c..2c05216 100644
--- a/Facepunch.Steamworks/Interfaces/Workshop.Item.cs
+++ b/Facepunch.Steamworks/Interfaces/Workshop.Item.cs
@@ -276,8 +276,8 @@ public string OwnerName
{
if ( _ownerName == null && workshop.friends != null )
{
- _ownerName = workshop.friends.GetName( OwnerId );
- if ( _ownerName == "[unknown]" )
+ _ownerName = workshop.friends.GetCachedName( OwnerId );
+ if ( _ownerName == Friends.DefaultName )
{
_ownerName = null;
return string.Empty;