Merge remote-tracking branch 'refs/remotes/Facepunch/master'

This commit is contained in:
Kyle Kukshtel 2017-08-07 09:24:49 -07:00
commit 9516d1ed7a
7 changed files with 166 additions and 34 deletions

View File

@ -19,7 +19,7 @@ public void StatsGet()
bool GotStats = false;
server.Stats.Refresh( MySteamId, success =>
server.Stats.Refresh( MySteamId, (steamid, success) =>
{
GotStats = true;
Assert.IsTrue( success );

View File

@ -13,21 +13,57 @@ public class Achievements : IDisposable
public Achievement[] All { get; private set; }
public event Action OnUpdated;
public event Action<Achievement> OnAchievementStateChanged;
private List<Achievement> unlockedRecently = new List<Achievement>();
internal Achievements( Client c )
{
client = c;
All = new Achievement[0];
SteamNative.UserStatsReceived_t.RegisterCallback( c, UserStatsReceived );
SteamNative.UserStatsStored_t.RegisterCallback( c, UserStatsStored );
Refresh();
}
public void Refresh()
{
var old = All;
All = Enumerable.Range( 0, (int)client.native.userstats.GetNumAchievements() )
.Select( x => new Achievement( client, x ) )
.Select( x =>
{
if ( old != null )
{
var name = client.native.userstats.GetAchievementName( (uint)x );
var found = old.FirstOrDefault( y => y.Id == name );
if ( found != null )
{
if ( found.Refresh() )
{
unlockedRecently.Add( found );
}
return found;
}
}
return new Achievement( client, x );
} )
.ToArray();
foreach ( var i in unlockedRecently )
{
OnUnlocked( i );
}
unlockedRecently.Clear();
}
internal void OnUnlocked( Achievement a )
{
OnAchievementStateChanged?.Invoke( a );
}
public void Dispose()
@ -50,14 +86,10 @@ public Achievement Find( string identifier )
/// </summary>
public bool Trigger( string identifier, bool apply = true )
{
var r = client.native.userstats.SetAchievement( identifier );
var a = Find( identifier );
if ( a == null ) return false;
if ( apply )
{
client.Stats.StoreStats();
}
return r;
return a.Trigger( apply );
}
/// <summary>
@ -71,6 +103,17 @@ public bool Reset( string identifier )
private void UserStatsReceived( UserStatsReceived_t stats, bool isError )
{
if ( isError ) return;
if ( stats.GameID != client.AppId ) return;
Refresh();
OnUpdated?.Invoke();
}
private void UserStatsStored( UserStatsStored_t stats, bool isError )
{
if ( isError ) return;
if ( stats.GameID != client.AppId ) return;
Refresh();
@ -97,6 +140,7 @@ public class Achievement
public DateTime UnlockTime { get; private set; }
private int iconId { get; set; } = -1;
private int refreshCount = 0;
/// <summary>
/// If this achievement is linked to a stat this will return the progress.
@ -159,6 +203,9 @@ public Achievement( Client client, int index )
/// </summary>
public bool Trigger( bool apply = true )
{
if ( State )
return false;
State = true;
UnlockTime = DateTime.Now;
@ -169,6 +216,8 @@ public bool Trigger( bool apply = true )
client.Stats.StoreStats();
}
client.Achievements.OnUnlocked( this );
return r;
}
@ -185,10 +234,12 @@ public bool Reset()
/// <summary>
/// Refresh the unlock state. You shouldn't need to call this manually
/// but it's here if you have to for some reason.
/// but it's here if you have to for some reason. Retuns true if state changed (meaning, probably unlocked)
/// </summary>
public void Refresh()
public bool Refresh()
{
bool previousState = State;
bool state = false;
uint unlockTime;
@ -199,6 +250,15 @@ public void Refresh()
State = state;
UnlockTime = Utility.Epoch.ToDateTime( unlockTime );
}
refreshCount++;
if ( previousState != State && refreshCount > 1 )
{
return true;
}
return false;
}
}

View File

@ -35,6 +35,8 @@ public enum RequestType
internal ulong BoardId;
internal Client client;
private readonly Queue<Action> _onCreated = new Queue<Action>();
/// <summary>
/// The results from the last query. Can be null.
/// </summary>
@ -77,21 +79,45 @@ public void Dispose()
client = null;
}
private void DispatchOnCreatedCallbacks()
{
while ( _onCreated.Count > 0 )
{
_onCreated.Dequeue()();
}
}
private bool DeferOnCreated( Action onValid, FailureCallback onFailure = null )
{
if ( IsValid || IsError ) return false;
_onCreated.Enqueue( () =>
{
if ( IsValid ) onValid();
else onFailure?.Invoke( Callbacks.Result.Fail );
} );
return true;
}
internal void OnBoardCreated( LeaderboardFindResult_t result, bool error )
{
if ( error || ( result.LeaderboardFound == 0 ) )
{
IsError = true;
return;
}
BoardId = result.SteamLeaderboard;
if ( IsValid )
else
{
Name = client.native.userstats.GetLeaderboardName( BoardId );
TotalEntries = client.native.userstats.GetLeaderboardEntryCount( BoardId );
BoardId = result.SteamLeaderboard;
if ( IsValid )
{
Name = client.native.userstats.GetLeaderboardName( BoardId );
TotalEntries = client.native.userstats.GetLeaderboardEntryCount( BoardId );
}
}
DispatchOnCreatedCallbacks();
}
/// <summary>
@ -103,7 +129,8 @@ internal void OnBoardCreated( LeaderboardFindResult_t result, bool error )
/// </summary>
public bool AddScore( bool onlyIfBeatsOldScore, int score, params int[] subscores )
{
if ( !IsValid ) return false;
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => AddScore( onlyIfBeatsOldScore, score, subscores ) );
var flags = LeaderboardUploadScoreMethod.ForceUpdate;
if ( onlyIfBeatsOldScore ) flags = LeaderboardUploadScoreMethod.KeepBest;
@ -142,7 +169,8 @@ public struct AddScoreResult
/// </summary>
public bool AddScore( bool onlyIfBeatsOldScore, int score, int[] subscores = null, AddScoreCallback onSuccess = null, FailureCallback onFailure = null )
{
if ( !IsValid ) return false;
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => AddScore( onlyIfBeatsOldScore, score, subscores, onSuccess, onFailure ), onFailure );
if ( subscores == null ) subscores = new int[0];
@ -182,7 +210,8 @@ public bool AddScore( bool onlyIfBeatsOldScore, int score, int[] subscores = nul
/// <returns>True if the file attachment process has started</returns>
public bool AttachRemoteFile( RemoteFile file, AttachRemoteFileCallback onSuccess = null, FailureCallback onFailure = null )
{
if ( !IsValid ) return false;
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => AttachRemoteFile( file, onSuccess, onFailure ), onFailure );
if ( file.IsShared )
{
@ -260,7 +289,8 @@ private unsafe void ReadScores( LeaderboardScoresDownloaded_t result, List<Entry
/// <returns>Returns true if we have started the query</returns>
public bool FetchScores( RequestType RequestType, int start, int end, FetchScoresCallback onSuccess, FailureCallback onFailure = null )
{
if ( !IsValid ) return false;
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => FetchScores( RequestType, start, end, onSuccess, onFailure ), onFailure );
client.native.userstats.DownloadLeaderboardEntries( BoardId, (LeaderboardDataRequest) RequestType, start, end, ( result, error ) =>
{

View File

@ -35,5 +35,36 @@ public void Trigger()
client.native.screenshots.TriggerScreenshot();
}
public unsafe void Write( byte[] rgbData, int width, int height )
{
if ( rgbData == null )
{
throw new ArgumentNullException( nameof(rgbData) );
}
if ( width < 1 )
{
throw new ArgumentOutOfRangeException( nameof(width), width,
$"Expected {nameof(width)} to be at least 1." );
}
if ( height < 1 )
{
throw new ArgumentOutOfRangeException( nameof(height), height,
$"Expected {nameof(height)} to be at least 1." );
}
var size = width * height * 3;
if ( rgbData.Length < size )
{
throw new ArgumentException( nameof(rgbData),
$"Expected {nameof(rgbData)} to contain at least {size} elements (actual size: {rgbData.Length})." );
}
fixed ( byte* ptr = rgbData )
{
client.native.screenshots.WriteScreenshot( (IntPtr) ptr, (uint) rgbData.Length, width, height );
}
}
}
}

View File

@ -63,6 +63,19 @@ public void Download( bool highPriority = true )
workshop.OnItemInstalled += OnItemInstalled;
}
public void Subscribe()
{
workshop.ugc.SubscribeItem(Id);
SubscriptionCount++;
}
public void UnSubscribe()
{
workshop.ugc.UnsubscribeItem(Id);
SubscriptionCount--;
}
private void OnFileDownloaded( ulong fileid, Callbacks.Result result )
{
if ( fileid != Id ) return;

View File

@ -29,8 +29,7 @@ public partial class Workshop : IDisposable
/// <summary>
/// Called when an item has been downloaded. This could have been
/// because of a call to Download or because of a subscription triggered
/// via the browser/app.
/// because of a call to Download.
/// </summary>
public event Action<ulong, Callbacks.Result> OnFileDownloaded;
@ -39,7 +38,7 @@ public partial class Workshop : IDisposable
/// because of a call to Download or because of a subscription triggered
/// via the browser/app.
/// </summary>
internal event Action<ulong> OnItemInstalled;
public event Action<ulong> OnItemInstalled;
internal Workshop( BaseSteamworks steamworks, SteamNative.SteamUGC ugc, SteamNative.SteamRemoteStorage remoteStorage )
{
@ -67,7 +66,7 @@ public void Dispose()
private void onItemInstalled( SteamNative.ItemInstalled_t obj, bool failed )
{
if ( OnItemInstalled != null )
if ( OnItemInstalled != null && obj.AppID == Client.Instance.AppId )
OnItemInstalled( obj.PublishedFileId );
}
@ -123,7 +122,6 @@ public Item GetItem( ulong itemid )
return new Item( itemid, this );
}
/// <summary>
/// How a query should be ordered.
/// </summary>

View File

@ -31,7 +31,7 @@ public struct StatsReceived
/// this will be called when the stats are recieved, the bool will signify whether
/// it was successful or not.
/// </summary>
public void Refresh( ulong steamid, Action<bool> Callback = null )
public void Refresh( ulong steamid, Action<ulong, bool> Callback = null )
{
if ( Callback == null )
{
@ -41,7 +41,7 @@ public void Refresh( ulong steamid, Action<bool> Callback = null )
server.native.gameServerStats.RequestUserStats( steamid, ( o, failed ) =>
{
Callback( o.Result == SteamNative.Result.OK && !failed );
Callback( steamid, o.Result == SteamNative.Result.OK && !failed );
} );
}
@ -50,7 +50,7 @@ public void Refresh( ulong steamid, Action<bool> Callback = null )
/// You can do that using this function. The callback will let you know if
/// your action succeeded, but most of the time you can fire and forget.
/// </summary>
public void Commit( ulong steamid, Action<bool> Callback = null )
public void Commit( ulong steamid, Action<ulong, bool> Callback = null )
{
if ( Callback == null )
{
@ -60,7 +60,7 @@ public void Commit( ulong steamid, Action<bool> Callback = null )
server.native.gameServerStats.StoreUserStats( steamid, ( o, failed ) =>
{
Callback( o.Result == SteamNative.Result.OK && !failed );
Callback( steamid, o.Result == SteamNative.Result.OK && !failed );
} );
}
@ -68,7 +68,7 @@ public void Commit( ulong steamid, Action<bool> Callback = null )
/// Set the named stat for this user. Setting stats should follow the rules
/// you defined in Steamworks.
/// </summary>
public bool Set( ulong steamid, string name, int stat )
public bool SetInt( ulong steamid, string name, int stat )
{
return server.native.gameServerStats.SetUserStat( steamid, name, stat );
}
@ -77,7 +77,7 @@ public bool Set( ulong steamid, string name, int stat )
/// Set the named stat for this user. Setting stats should follow the rules
/// you defined in Steamworks.
/// </summary>
public bool Set( ulong steamid, string name, float stat )
public bool SetFloat( ulong steamid, string name, float stat )
{
return server.native.gameServerStats.SetUserStat0( steamid, name, stat );
}