mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-25 14:15:47 +03:00
Fixed downloading leaderboard file attachments
This commit is contained in:
parent
836f6e285c
commit
7e3527799a
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
@ -169,5 +170,72 @@ public void AddScoresCallback()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void AddFileAttachment()
|
||||||
|
{
|
||||||
|
using ( var client = new Steamworks.Client( 252490 ) )
|
||||||
|
{
|
||||||
|
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
|
||||||
|
|
||||||
|
while ( !board.IsValid )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue( board.IsValid );
|
||||||
|
Assert.IsFalse( board.IsError );
|
||||||
|
|
||||||
|
var done = false;
|
||||||
|
|
||||||
|
const int score = 5678;
|
||||||
|
const string attachment = "Hello world!";
|
||||||
|
|
||||||
|
var file = client.RemoteStorage.CreateFile( "score/example.txt" );
|
||||||
|
file.WriteAllText( attachment );
|
||||||
|
|
||||||
|
Assert.IsTrue( board.AddScore( false, score, null, ( success, result ) =>
|
||||||
|
{
|
||||||
|
Assert.IsTrue( success );
|
||||||
|
Assert.IsTrue( result.ScoreChanged );
|
||||||
|
|
||||||
|
Assert.IsTrue( board.AttachRemoteFile( file, attached =>
|
||||||
|
{
|
||||||
|
Assert.IsTrue( attached );
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
} ) );
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
while ( !done )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
done = false;
|
||||||
|
|
||||||
|
Assert.IsTrue( board.FetchScores( Steamworks.Leaderboard.RequestType.GlobalAroundUser, 0, 0, ( success, entries ) =>
|
||||||
|
{
|
||||||
|
Assert.AreEqual( 1, entries.Length );
|
||||||
|
Assert.IsNotNull( entries[0].AttachedFile );
|
||||||
|
|
||||||
|
Assert.IsTrue( entries[0].AttachedFile.Download( downloaded =>
|
||||||
|
{
|
||||||
|
Assert.IsTrue( downloaded );
|
||||||
|
Assert.AreEqual( attachment, entries[0].AttachedFile.ReadAllText() );
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
} ) );
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
while ( !done )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -177,22 +177,20 @@ public bool AttachRemoteFile( RemoteFile file, AttachRemoteFileCallback callback
|
|||||||
|
|
||||||
if ( file.IsShared )
|
if ( file.IsShared )
|
||||||
{
|
{
|
||||||
client.native.userstats.AttachLeaderboardUGC( BoardId, file.UGCHandle, ( result, error ) =>
|
var handle = client.native.userstats.AttachLeaderboardUGC( BoardId, file.UGCHandle, ( result, error ) =>
|
||||||
{
|
{
|
||||||
callback?.Invoke( !error && result.Result == Result.OK );
|
callback?.Invoke( !error && result.Result == Result.OK );
|
||||||
} );
|
} );
|
||||||
return true;
|
|
||||||
|
return handle.CallResultHandle != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.Share( success =>
|
file.Share( success =>
|
||||||
{
|
{
|
||||||
if ( !success || !file.IsShared )
|
if ( !success || !file.IsShared || !AttachRemoteFile( file, callback ) )
|
||||||
{
|
{
|
||||||
callback?.Invoke( false );
|
callback?.Invoke( false );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachRemoteFile( file, callback );
|
|
||||||
} );
|
} );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -226,7 +224,8 @@ private unsafe void ReadScores( LeaderboardScoresDownloaded_t result, List<Entry
|
|||||||
Score = entry.Score,
|
Score = entry.Score,
|
||||||
SteamId = entry.SteamIDUser,
|
SteamId = entry.SteamIDUser,
|
||||||
SubScores = entry.CDetails == 0 ? null : subEntriesBuffer.Take( entry.CDetails ).ToArray(),
|
SubScores = entry.CDetails == 0 ? null : subEntriesBuffer.Take( entry.CDetails ).ToArray(),
|
||||||
Name = client.Friends.GetName( entry.SteamIDUser )
|
Name = client.Friends.GetName( entry.SteamIDUser ),
|
||||||
|
AttachedFile = (entry.UGC >> 32) == 0xffffffff ? null : new RemoteFile( client.RemoteStorage, entry.UGC )
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,7 +287,7 @@ public struct Entry
|
|||||||
public int Score;
|
public int Score;
|
||||||
public int[] SubScores;
|
public int[] SubScores;
|
||||||
public int GlobalRank;
|
public int GlobalRank;
|
||||||
|
public RemoteFile AttachedFile;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Note that the player's name might not be immediately available.
|
/// Note that the player's name might not be immediately available.
|
||||||
|
@ -125,11 +125,18 @@ public class RemoteFile
|
|||||||
private UGCHandle_t _handle;
|
private UGCHandle_t _handle;
|
||||||
private ulong _ownerId;
|
private ulong _ownerId;
|
||||||
|
|
||||||
|
private bool _isDownloading;
|
||||||
|
private byte[] _downloadedData;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if the file exists.
|
/// Check if the file exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exists { get; internal set; }
|
public bool Exists { get; internal set; }
|
||||||
|
|
||||||
|
public bool IsDownloading { get { return _isUgc && _isDownloading && _downloadedData == null; } }
|
||||||
|
|
||||||
|
public bool IsDownloaded { get { return !_isUgc || _downloadedData != null; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, the file is available for other users to download.
|
/// If true, the file is available for other users to download.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -137,6 +144,8 @@ public class RemoteFile
|
|||||||
|
|
||||||
internal UGCHandle_t UGCHandle { get { return _handle; } }
|
internal UGCHandle_t UGCHandle { get { return _handle; } }
|
||||||
|
|
||||||
|
public ulong SharingId { get { return UGCHandle.Value; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name and path of the file.
|
/// Name and path of the file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -201,7 +210,6 @@ internal RemoteFile( RemoteStorage r, string name, ulong ownerId, int sizeInByte
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="RemoteFileWriteStream"/> used to write to this file.
|
/// Creates a <see cref="RemoteFileWriteStream"/> used to write to this file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
|
||||||
public RemoteFileWriteStream OpenWrite()
|
public RemoteFileWriteStream OpenWrite()
|
||||||
{
|
{
|
||||||
return new RemoteFileWriteStream( remoteStorage, this );
|
return new RemoteFileWriteStream( remoteStorage, this );
|
||||||
@ -227,6 +235,62 @@ public void WriteAllText( string text, Encoding encoding = null )
|
|||||||
WriteAllBytes( encoding.GetBytes( text ) );
|
WriteAllBytes( encoding.GetBytes( text ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback invoked by <see cref="RemoteFile.Download"/> when a file download is complete.
|
||||||
|
/// </summary>
|
||||||
|
public delegate void DownloadCallback( bool success );
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of bytes downloaded and the total number of bytes expected while
|
||||||
|
/// this file is downloading.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the file is downloading</returns>
|
||||||
|
public bool GetDownloadProgress( out int bytesDownloaded, out int bytesExpected )
|
||||||
|
{
|
||||||
|
return remoteStorage.native.GetUGCDownloadProgress( _handle, out bytesDownloaded, out bytesExpected );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to start downloading a shared file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the download has successfully started</returns>
|
||||||
|
public bool Download( DownloadCallback callback = null )
|
||||||
|
{
|
||||||
|
if ( !_isUgc ) return false;
|
||||||
|
if ( _isDownloading ) return false;
|
||||||
|
if ( IsDownloaded ) return false;
|
||||||
|
|
||||||
|
_isDownloading = true;
|
||||||
|
|
||||||
|
remoteStorage.native.UGCDownload( _handle, 1000, ( result, error ) =>
|
||||||
|
{
|
||||||
|
_isDownloading = false;
|
||||||
|
|
||||||
|
if ( error || result.Result != Result.OK )
|
||||||
|
{
|
||||||
|
callback?.Invoke( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ownerId = result.SteamIDOwner;
|
||||||
|
_sizeInBytes = result.SizeInBytes;
|
||||||
|
_fileName = result.PchFileName;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
_downloadedData = new byte[_sizeInBytes];
|
||||||
|
fixed ( byte* bufferPtr = _downloadedData )
|
||||||
|
{
|
||||||
|
remoteStorage.native.UGCRead( _handle, (IntPtr) bufferPtr, _sizeInBytes, 0, UGCReadAction.ontinueReading );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback?.Invoke( true );
|
||||||
|
} );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens a stream used to read from this file.
|
/// Opens a stream used to read from this file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -243,8 +307,8 @@ public unsafe byte[] ReadAllBytes()
|
|||||||
{
|
{
|
||||||
if ( _isUgc )
|
if ( _isUgc )
|
||||||
{
|
{
|
||||||
// Need to download
|
if ( !IsDownloaded ) throw new Exception( "Cannot read a file that hasn't been downloaded." );
|
||||||
throw new NotImplementedException();
|
return _downloadedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
var size = SizeInBytes;
|
var size = SizeInBytes;
|
||||||
|
@ -14929,7 +14929,7 @@ public static void RegisterCallback( Facepunch.Steamworks.BaseSteamworks steamwo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout( LayoutKind.Sequential, Pack = 4 )]
|
[StructLayout( LayoutKind.Sequential, Pack = 8 )]
|
||||||
internal struct LeaderboardEntry_t
|
internal struct LeaderboardEntry_t
|
||||||
{
|
{
|
||||||
public ulong SteamIDUser; // m_steamIDUser class CSteamID
|
public ulong SteamIDUser; // m_steamIDUser class CSteamID
|
||||||
|
@ -30,6 +30,11 @@ public class TypeDef
|
|||||||
"CCallbackBase"
|
"CCallbackBase"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public readonly static string[] ForceLargePackStructs = new string[]
|
||||||
|
{
|
||||||
|
"LeaderboardEntry_t"
|
||||||
|
};
|
||||||
|
|
||||||
void Structs()
|
void Structs()
|
||||||
{
|
{
|
||||||
foreach ( var c in def.structs )
|
foreach ( var c in def.structs )
|
||||||
@ -42,7 +47,7 @@ void Structs()
|
|||||||
|
|
||||||
int defaultPack = 8;
|
int defaultPack = 8;
|
||||||
|
|
||||||
if ( c.Fields.Any( x => x.Type.Contains( "class CSteamID" ) ) )
|
if ( c.Fields.Any( x => x.Type.Contains( "class CSteamID" ) ) && !ForceLargePackStructs.Contains( c.Name ) )
|
||||||
defaultPack = 4;
|
defaultPack = 4;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user