mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-24 13:45:37 +03:00
Cleaner approach for fetching usernames
This commit is contained in:
parent
7c4aaddd1c
commit
605054339a
@ -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 = " -:+#";
|
||||
|
@ -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() ) );
|
||||
|
@ -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"));
|
||||
|
@ -121,13 +121,12 @@ public bool UpdateInformation( ulong steamid )
|
||||
{
|
||||
return !client.native.friends.RequestUserInformation( steamid, false );
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get this user's name
|
||||
/// Get this user's name immediately. This should work for people on your friends list.
|
||||
/// </summary>
|
||||
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<Image> 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<Image> callback )
|
||||
// if not it'll time out anyway
|
||||
}
|
||||
|
||||
PersonaCallbacks.Add( new PersonaCallback
|
||||
AvatarCallbacks.Add( new PersonaCallback<Image>
|
||||
{
|
||||
SteamId = steamid,
|
||||
Size = size,
|
||||
@ -296,15 +295,54 @@ public void GetAvatar( AvatarSize size, ulong steamid, Action<Image> callback )
|
||||
});
|
||||
}
|
||||
|
||||
private class PersonaCallback
|
||||
public const string DefaultName = "[unknown]";
|
||||
|
||||
public void GetName( ulong steamid, Action<string> 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<string>
|
||||
{
|
||||
SteamId = steamid,
|
||||
Callback = callback,
|
||||
Time = DateTime.Now
|
||||
} );
|
||||
}
|
||||
|
||||
private class PersonaCallback<T>
|
||||
{
|
||||
public ulong SteamId;
|
||||
public AvatarSize Size;
|
||||
public Action<Image> Callback;
|
||||
public Action<T> Callback;
|
||||
public DateTime Time;
|
||||
}
|
||||
|
||||
List<PersonaCallback> PersonaCallbacks = new List<PersonaCallback>();
|
||||
List<PersonaCallback<Image>> AvatarCallbacks = new List<PersonaCallback<Image>>();
|
||||
List<PersonaCallback<string>> NameCallbacks = new List<PersonaCallback<string>>();
|
||||
|
||||
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<T>( List<PersonaCallback<T>> callbacks, Func<PersonaCallback<T>, 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<ulong, Dictionary<int, FetchInformationCallback>> _fetchInformationRequests =
|
||||
new Dictionary<ulong, Dictionary<int, FetchInformationCallback>>();
|
||||
private static readonly List<KeyValuePair<int, FetchInformationCallback>> _tempCallbackList
|
||||
= new List<KeyValuePair<int, FetchInformationCallback>>();
|
||||
|
||||
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<int, FetchInformationCallback>();
|
||||
_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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,6 @@ private unsafe void ReadScores( LeaderboardScoresDownloaded_t result, List<Entry
|
||||
Score = entry.Score,
|
||||
SteamId = entry.SteamIDUser,
|
||||
SubScores = entry.CDetails == 0 ? null : subEntriesBuffer.Take( entry.CDetails ).ToArray(),
|
||||
Name = client.Friends.GetName( entry.SteamIDUser ),
|
||||
AttachedFile = (entry.UGC >> 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;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public string Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user