diff --git a/Facepunch.Steamworks/SteamServerStats.cs b/Facepunch.Steamworks/SteamServerStats.cs
new file mode 100644
index 0000000..239807a
--- /dev/null
+++ b/Facepunch.Steamworks/SteamServerStats.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Steamworks.Data;
+
+namespace Steamworks
+{
+ public static class SteamServerStats
+ {
+ static ISteamGameServerStats _internal;
+ internal static ISteamGameServerStats Internal
+ {
+ get
+ {
+ if ( _internal == null )
+ {
+ _internal = new ISteamGameServerStats();
+ _internal.InitServer();
+ }
+
+ return _internal;
+ }
+ }
+
+ internal static void Shutdown()
+ {
+ _internal = null;
+ }
+
+ ///
+ /// Downloads stats for the user
+ /// If the user has no stats will return fail
+ /// these stats will only be auto-updated for clients playing on the server
+ ///
+ public static async Task RequestUserStats( SteamId steamid )
+ {
+ var r = await Internal.RequestUserStats( steamid );
+ if ( !r.HasValue ) return Result.Fail;
+ return r.Value.Result;
+ }
+
+ ///
+ /// Set the named stat for this user. Setting stats should follow the rules
+ /// you defined in Steamworks.
+ ///
+ public static bool SetInt( SteamId steamid, string name, int stat )
+ {
+ return Internal.SetUserStat1( steamid, name, stat );
+ }
+
+ ///
+ /// Set the named stat for this user. Setting stats should follow the rules
+ /// you defined in Steamworks.
+ ///
+ public static bool SetFloat( SteamId steamid, string name, float stat )
+ {
+ return Internal.SetUserStat2( steamid, name, stat );
+ }
+
+ ///
+ /// Get the named stat for this user. If getting the stat failed, will return
+ /// defaultValue. You should have called Refresh for this userid - which downloads
+ /// the stats from the backend. If you didn't call it this will always return defaultValue.
+ ///
+ public static int GetInt( SteamId steamid, string name, int defaultValue = 0 )
+ {
+ int data = defaultValue;
+
+ if ( !Internal.GetUserStat1( steamid, name, ref data ) )
+ return defaultValue;
+
+ return data;
+ }
+
+ ///
+ /// Get the named stat for this user. If getting the stat failed, will return
+ /// defaultValue. You should have called Refresh for this userid - which downloads
+ /// the stats from the backend. If you didn't call it this will always return defaultValue.
+ ///
+ public static float GetFloat( SteamId steamid, string name, float defaultValue = 0 )
+ {
+ float data = defaultValue;
+
+ if ( !Internal.GetUserStat2( steamid, name, ref data ) )
+ return defaultValue;
+
+ return data;
+ }
+
+ ///
+ /// Unlocks the specified achievement for the specified user. Must have called Refresh on a steamid first.
+ /// Remember to use Commit after use.
+ ///
+ public static bool SetAchievement( SteamId steamid, string name )
+ {
+ return Internal.SetUserAchievement( steamid, name );
+ }
+
+ ///
+ /// Resets the unlock status of an achievement for the specified user. Must have called Refresh on a steamid first.
+ /// Remember to use Commit after use.
+ ///
+ public static bool ClearAchievement( SteamId steamid, string name )
+ {
+ return Internal.ClearUserAchievement( steamid, name );
+ }
+
+ ///
+ /// Return true if available, exists and unlocked
+ ///
+ public static bool GetAchievement( SteamId steamid, string name )
+ {
+ bool achieved = false;
+
+ if ( !Internal.GetUserAchievement( steamid, name, ref achieved ) )
+ return false;
+
+ return achieved;
+ }
+
+ ///
+ /// Once you've set a stat change on a user you need to commit your changes.
+ /// 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.
+ ///
+ public static async Task StoreUserStats( SteamId steamid )
+ {
+ var r = await Internal.StoreUserStats( steamid );
+ if ( !r.HasValue ) return Result.Fail;
+ return r.Value.Result;
+ }
+ }
+}
\ No newline at end of file