diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..43d0120 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +zlib License + +Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. \ No newline at end of file diff --git a/SAM.API/Callback.cs b/SAM.API/Callback.cs new file mode 100644 index 0000000..3c7de59 --- /dev/null +++ b/SAM.API/Callback.cs @@ -0,0 +1,59 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API +{ + public abstract class Callback : ICallback + { + public delegate void CallbackFunction(IntPtr param); + + public event CallbackFunction OnRun; + + public abstract int Id { get; } + public abstract bool IsServer { get; } + + public void Run(IntPtr param) + { + this.OnRun(param); + } + } + + public abstract class Callback : ICallback + where TParameter : struct + { + public delegate void CallbackFunction(TParameter arg); + + public event CallbackFunction OnRun; + + public abstract int Id { get; } + public abstract bool IsServer { get; } + + public void Run(IntPtr pvParam) + { + var data = (TParameter)Marshal.PtrToStructure(pvParam, typeof(TParameter)); + this.OnRun(data); + } + } +} diff --git a/SAM.API/Callbacks/AppDataChanged.cs b/SAM.API/Callbacks/AppDataChanged.cs new file mode 100644 index 0000000..62bc835 --- /dev/null +++ b/SAM.API/Callbacks/AppDataChanged.cs @@ -0,0 +1,37 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.API.Callbacks +{ + public class AppDataChanged : Callback + { + public override int Id + { + get { return 1001; } + } + + public override bool IsServer + { + get { return false; } + } + } +} diff --git a/SAM.API/Callbacks/UserStatsReceived.cs b/SAM.API/Callbacks/UserStatsReceived.cs new file mode 100644 index 0000000..48fea25 --- /dev/null +++ b/SAM.API/Callbacks/UserStatsReceived.cs @@ -0,0 +1,37 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.API.Callbacks +{ + public class UserStatsReceived : Callback + { + public override int Id + { + get { return 1101; } + } + + public override bool IsServer + { + get { return false; } + } + } +} diff --git a/SAM.API/Client.cs b/SAM.API/Client.cs new file mode 100644 index 0000000..edbed7d --- /dev/null +++ b/SAM.API/Client.cs @@ -0,0 +1,140 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace SAM.API +{ + public class Client + { + public Wrappers.SteamClient009 SteamClient; + public Wrappers.SteamUser012 SteamUser; + public Wrappers.SteamUserStats007 SteamUserStats; + public Wrappers.SteamUtils005 SteamUtils; + public Wrappers.SteamApps001 SteamApps001; + public Wrappers.SteamApps003 SteamApps003; + + private int _Pipe; + private int _User; + + private readonly List _Callbacks = new List(); + + public bool Initialize(long appId) + { + if (appId != 0) + { + Environment.SetEnvironmentVariable("SteamAppId", appId.ToString(CultureInfo.InvariantCulture)); + } + + if (Steam.GetInstallPath() == null) + { + return false; + } + + if (Steam.Load() == false) + { + return false; + } + + this.SteamClient = Steam.CreateInterface("SteamClient009"); + if (this.SteamClient == null) + { + return false; + } + + this._Pipe = this.SteamClient.CreateSteamPipe(); + if (this._Pipe == 0) + { + return false; + } + + this._User = this.SteamClient.ConnectToGlobalUser(this._Pipe); + if (this._User == 0) + { + return false; + } + + this.SteamUtils = this.SteamClient.GetSteamUtils004(this._Pipe); + if (appId > 0 && this.SteamUtils.GetAppId() != (uint)appId) + { + return false; + } + + this.SteamUser = this.SteamClient.GetSteamUser012(this._User, this._Pipe); + this.SteamUserStats = this.SteamClient.GetSteamUserStats006(this._User, this._Pipe); + this.SteamApps001 = this.SteamClient.GetSteamApps001(this._User, this._Pipe); + this.SteamApps003 = this.SteamClient.GetSteamApps003(this._User, this._Pipe); + return true; + } + + ~Client() + { + if (this.SteamClient != null) + { + this.SteamClient.ReleaseUser(this._Pipe, this._User); + this._User = 0; + this.SteamClient.ReleaseSteamPipe(this._Pipe); + this._Pipe = 0; + } + } + + public TCallback CreateAndRegisterCallback() + where TCallback : ICallback, new() + { + var callback = new TCallback(); + this._Callbacks.Add(callback); + return callback; + } + + private bool _RunningCallbacks; + + public void RunCallbacks(bool server) + { + if (this._RunningCallbacks == true) + { + return; + } + + this._RunningCallbacks = true; + + Types.CallbackMessage message; + int call; + while (Steam.GetCallback(this._Pipe, out message, out call) == true) + { + var callbackId = message.Id; + foreach (ICallback callback in this._Callbacks.Where( + candidate => candidate.Id == callbackId && + candidate.IsServer == server)) + { + callback.Run(message.ParamPointer); + } + + Steam.FreeLastCallback(this._Pipe); + } + + this._RunningCallbacks = false; + } + } +} diff --git a/SAM.API/ICallback.cs b/SAM.API/ICallback.cs new file mode 100644 index 0000000..174e64e --- /dev/null +++ b/SAM.API/ICallback.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; + +namespace SAM.API +{ + public interface ICallback + { + int Id { get; } + bool IsServer { get; } + void Run(IntPtr param); + } +} diff --git a/SAM.API/INativeWrapper.cs b/SAM.API/INativeWrapper.cs new file mode 100644 index 0000000..d8e865f --- /dev/null +++ b/SAM.API/INativeWrapper.cs @@ -0,0 +1,31 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; + +namespace SAM.API +{ + public interface INativeWrapper + { + void SetupFunctions(IntPtr objectAddress); + } +} diff --git a/SAM.API/Interfaces/ISteamApps001.cs b/SAM.API/Interfaces/ISteamApps001.cs new file mode 100644 index 0000000..200921e --- /dev/null +++ b/SAM.API/Interfaces/ISteamApps001.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ISteamApps001 + { + public IntPtr GetAppData; + } +} diff --git a/SAM.API/Interfaces/ISteamApps003.cs b/SAM.API/Interfaces/ISteamApps003.cs new file mode 100644 index 0000000..1a1603f --- /dev/null +++ b/SAM.API/Interfaces/ISteamApps003.cs @@ -0,0 +1,40 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ISteamApps003 + { + public IntPtr IsSubscribed; + public IntPtr IsLowViolence; + public IntPtr IsCybercafe; + public IntPtr IsVACBanned; + public IntPtr GetCurrentGameLanguage; + public IntPtr GetAvailableGameLanguages; + public IntPtr IsSubscribedApp; + public IntPtr IsDlcInstalled; + } +} diff --git a/SAM.API/Interfaces/ISteamClient009.cs b/SAM.API/Interfaces/ISteamClient009.cs new file mode 100644 index 0000000..466ef85 --- /dev/null +++ b/SAM.API/Interfaces/ISteamClient009.cs @@ -0,0 +1,54 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ISteamClient009 + { + public IntPtr CreateSteamPipe; + public IntPtr ReleaseSteamPipe; + public IntPtr ConnectToGlobalUser; + public IntPtr CreateLocalUser; + public IntPtr ReleaseUser; + public IntPtr GetISteamUser; + public IntPtr GetISteamGameServer; + public IntPtr SetLocalIPBinding; + public IntPtr GetISteamFriends; + public IntPtr GetISteamUtils; + public IntPtr GetISteamMatchmaking; + public IntPtr GetISteamMasterServerUpdater; + public IntPtr GetISteamMatchmakingServers; + public IntPtr GetISteamGenericInterface; + public IntPtr GetISteamUserStats; + public IntPtr GetISteamGameServerStats; + public IntPtr GetISteamApps; + public IntPtr GetISteamNetworking; + public IntPtr GetISteamRemoteStorage; + public IntPtr RunFrame; + public IntPtr GetIPCCallCount; + public IntPtr SetWarningMessageHook; + } +} diff --git a/SAM.API/Interfaces/ISteamUser012.cs b/SAM.API/Interfaces/ISteamUser012.cs new file mode 100644 index 0000000..a4c756e --- /dev/null +++ b/SAM.API/Interfaces/ISteamUser012.cs @@ -0,0 +1,48 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ISteamUser012 + { + public IntPtr GetHSteamUser; + public IntPtr LoggedOn; + public IntPtr GetSteamID; + public IntPtr InitiateGameConnection; + public IntPtr TerminateGameConnection; + public IntPtr TrackAppUsageEvent; + public IntPtr GetUserDataFolder; + public IntPtr StartVoiceRecording; + public IntPtr StopVoiceRecording; + public IntPtr GetCompressedVoice; + public IntPtr DecompressVoice; + public IntPtr GetAuthSessionTicket; + public IntPtr BeginAuthSession; + public IntPtr EndAuthSession; + public IntPtr CancelAuthTicket; + public IntPtr UserHasLicenseForApp; + } +} diff --git a/SAM.API/Interfaces/ISteamUserStats007.cs b/SAM.API/Interfaces/ISteamUserStats007.cs new file mode 100644 index 0000000..ec24183 --- /dev/null +++ b/SAM.API/Interfaces/ISteamUserStats007.cs @@ -0,0 +1,62 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class ISteamUserStats007 + { + public IntPtr RequestCurrentStats; + public IntPtr GetStatFloat; + public IntPtr GetStatInteger; + public IntPtr SetStatFloat; + public IntPtr SetStatInteger; + public IntPtr UpdateAvgRateStat; + public IntPtr GetAchievement; + public IntPtr SetAchievement; + public IntPtr ClearAchievement; + public IntPtr GetAchievementAndUnlockTime; + public IntPtr StoreStats; + public IntPtr GetAchievementIcon; + public IntPtr GetAchievementDisplayAttribute; + public IntPtr IndicateAchievementProgress; + public IntPtr RequestUserStats; + public IntPtr GetUserStatFloat; + public IntPtr GetUserStatInt; + public IntPtr GetUserAchievement; + public IntPtr GetUserAchievementAndUnlockTime; + public IntPtr ResetAllStats; + public IntPtr FindOrCreateLeaderboard; + public IntPtr FindLeaderboard; + public IntPtr GetLeaderboardName; + public IntPtr GetLeaderboardEntryCount; + public IntPtr GetLeaderboardSortMethod; + public IntPtr GetLeaderboardDisplayType; + public IntPtr DownloadLeaderboardEntries; + public IntPtr GetDownloadedLeaderboardEntry; + public IntPtr UploadLeaderboardScore; + public IntPtr GetNumberOfCurrentPlayers; + } +} diff --git a/SAM.API/Interfaces/ISteamUtils005.cs b/SAM.API/Interfaces/ISteamUtils005.cs new file mode 100644 index 0000000..0bb6548 --- /dev/null +++ b/SAM.API/Interfaces/ISteamUtils005.cs @@ -0,0 +1,51 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ISteamUtils005 + { + public IntPtr GetSecondsSinceAppActive; + public IntPtr GetSecondsSinceComputerActive; + public IntPtr GetConnectedUniverse; + public IntPtr GetServerRealTime; + public IntPtr GetIPCountry; + public IntPtr GetImageSize; + public IntPtr GetImageRGBA; + public IntPtr GetCSERIPPort; + public IntPtr GetCurrentBatteryPower; + public IntPtr GetAppID; + public IntPtr SetOverlayNotificationPosition; + public IntPtr IsAPICallCompleted; + public IntPtr GetAPICallFailureReason; + public IntPtr GetAPICallResult; + public IntPtr RunFrame; + public IntPtr GetIPCCallCount; + public IntPtr SetWarningMessageHook; + public IntPtr IsOverlayEnabled; + public IntPtr OverlayNeedsPresent; + } +} diff --git a/SAM.API/LICENSE.txt b/SAM.API/LICENSE.txt new file mode 100644 index 0000000..43d0120 --- /dev/null +++ b/SAM.API/LICENSE.txt @@ -0,0 +1,22 @@ +zlib License + +Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. \ No newline at end of file diff --git a/SAM.API/NativeClass.cs b/SAM.API/NativeClass.cs new file mode 100644 index 0000000..dddeb28 --- /dev/null +++ b/SAM.API/NativeClass.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API +{ + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + internal struct NativeClass + { + public IntPtr VirtualTable; + } +} diff --git a/SAM.API/NativeWrapper.cs b/SAM.API/NativeWrapper.cs new file mode 100644 index 0000000..769bdc0 --- /dev/null +++ b/SAM.API/NativeWrapper.cs @@ -0,0 +1,90 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace SAM.API +{ + public abstract class NativeWrapper : INativeWrapper + { + protected IntPtr ObjectAddress; + protected TNativeFunctions Functions; + + public override string ToString() + { + return string.Format( + "Steam Interface<{0}> #{1:X8}", + typeof(TNativeFunctions), + this.ObjectAddress.ToInt32()); + } + + public void SetupFunctions(IntPtr objectAddress) + { + this.ObjectAddress = objectAddress; + + var iface = (NativeClass)Marshal.PtrToStructure( + this.ObjectAddress, + typeof(NativeClass)); + + this.Functions = (TNativeFunctions)Marshal.PtrToStructure( + iface.VirtualTable, + typeof(TNativeFunctions)); + } + + private readonly Dictionary _FunctionCache = new Dictionary(); + + protected Delegate GetDelegate(IntPtr pointer) + { + Delegate function; + + if (this._FunctionCache.ContainsKey(pointer) == false) + { + function = Marshal.GetDelegateForFunctionPointer(pointer, typeof(TDelegate)); + this._FunctionCache[pointer] = function; + } + else + { + function = this._FunctionCache[pointer]; + } + + return function; + } + + protected TDelegate GetFunction(IntPtr pointer) + where TDelegate : class + { + return (TDelegate)((object)this.GetDelegate(pointer)); + } + + protected void Call(IntPtr pointer, params object[] args) + { + this.GetDelegate(pointer).DynamicInvoke(args); + } + + protected TReturn Call(IntPtr pointer, params object[] args) + { + return (TReturn)this.GetDelegate(pointer).DynamicInvoke(args); + } + } +} diff --git a/SAM.API/Pink.ico b/SAM.API/Pink.ico new file mode 100644 index 0000000..e19cf76 Binary files /dev/null and b/SAM.API/Pink.ico differ diff --git a/SAM.API/Properties/AssemblyInfo.cs b/SAM.API/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..39e5d9f --- /dev/null +++ b/SAM.API/Properties/AssemblyInfo.cs @@ -0,0 +1,61 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("Steam Achievement Manager API")] +[assembly: AssemblyDescription("Easy to use classes for accessing the Steam API.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Gibbed")] +[assembly: AssemblyProduct("SAM.API")] +[assembly: AssemblyCopyright("Copyright © Gibbed 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("5a9771a4-ca63-42aa-bbf6-0b2a0147a8ea")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] + +[assembly: AssemblyVersion("7.0.0.0")] +[assembly: AssemblyFileVersion("7.0.0.0")] diff --git a/SAM.API/SAM.API.csproj b/SAM.API/SAM.API.csproj new file mode 100644 index 0000000..9a8015c --- /dev/null +++ b/SAM.API/SAM.API.csproj @@ -0,0 +1,128 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1} + Library + Properties + SAM.API + SAM.API + v3.5 + 512 + Pink.ico + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x86 + AllRules.ruleset + + + none + true + ..\upload\ + TRACE + prompt + 4 + x86 + false + AllRules.ruleset + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/SAM.API/SAM.API.csproj.DotSettings b/SAM.API/SAM.API.csproj.DotSettings new file mode 100644 index 0000000..6e7fff8 --- /dev/null +++ b/SAM.API/SAM.API.csproj.DotSettings @@ -0,0 +1,2 @@ + + No \ No newline at end of file diff --git a/SAM.API/Steam.cs b/SAM.API/Steam.cs new file mode 100644 index 0000000..3fc9ef7 --- /dev/null +++ b/SAM.API/Steam.cs @@ -0,0 +1,151 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.IO; +using System.Runtime.InteropServices; +using Microsoft.Win32; + +namespace SAM.API +{ + public static class Steam + { + private struct Native + { + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr GetProcAddress(IntPtr module, string name); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr LoadLibraryEx(string path, IntPtr file, uint flags); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr SetDllDirectory(string path); + + internal const uint LoadWithAlteredSearchPath = 8; + } + + private static Delegate GetExportDelegate(IntPtr module, string name) + { + IntPtr address = Native.GetProcAddress(module, name); + return address == IntPtr.Zero ? null : Marshal.GetDelegateForFunctionPointer(address, typeof(TDelegate)); + } + + private static TDelegate GetExportFunction(IntPtr module, string name) + where TDelegate : class + { + return (TDelegate)((object)GetExportDelegate(module, name)); + } + + private static IntPtr _Handle = IntPtr.Zero; + + public static string GetInstallPath() + { + return (string)Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Valve\Steam", "InstallPath", null); + } + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + private delegate IntPtr NativeCreateInterface(string version, IntPtr returnCode); + + private static NativeCreateInterface _CallCreateInterface; + + public static TClass CreateInterface(string version) + where TClass : INativeWrapper, new() + { + IntPtr address = _CallCreateInterface(version, IntPtr.Zero); + + if (address == IntPtr.Zero) + { + return default(TClass); + } + + var rez = new TClass(); + rez.SetupFunctions(address); + return rez; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeSteamGetCallback(int pipe, out Types.CallbackMessage message, out int call); + + private static NativeSteamGetCallback _CallSteamBGetCallback; + + public static bool GetCallback(int pipe, out Types.CallbackMessage message, out int call) + { + return _CallSteamBGetCallback(pipe, out message, out call); + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeSteamFreeLastCallback(int pipe); + + private static NativeSteamFreeLastCallback _CallSteamFreeLastCallback; + + public static bool FreeLastCallback(int pipe) + { + return _CallSteamFreeLastCallback(pipe); + } + + public static bool Load() + { + if (_Handle != IntPtr.Zero) + { + return true; + } + + string path = GetInstallPath(); + if (path == null) + { + return false; + } + + Native.SetDllDirectory(path + ";" + Path.Combine(path, "bin")); + + path = Path.Combine(path, "steamclient.dll"); + IntPtr module = Native.LoadLibraryEx(path, IntPtr.Zero, Native.LoadWithAlteredSearchPath); + if (module == IntPtr.Zero) + { + return false; + } + + _CallCreateInterface = GetExportFunction(module, "CreateInterface"); + if (_CallCreateInterface == null) + { + return false; + } + + _CallSteamBGetCallback = GetExportFunction(module, "Steam_BGetCallback"); + if (_CallSteamBGetCallback == null) + { + return false; + } + + _CallSteamFreeLastCallback = GetExportFunction(module, "Steam_FreeLastCallback"); + if (_CallSteamFreeLastCallback == null) + { + return false; + } + + _Handle = module; + return true; + } + } +} diff --git a/SAM.API/Types/.svn/all-wcprops b/SAM.API/Types/.svn/all-wcprops new file mode 100644 index 0000000..ef80839 --- /dev/null +++ b/SAM.API/Types/.svn/all-wcprops @@ -0,0 +1,35 @@ +K 25 +svn:wc:ra_dav:version-url +V 63 +/private/steam/!svn/ver/3/branches/SAM/SAM.API/Interfaces/Types +END +UserStatType.cs +K 25 +svn:wc:ra_dav:version-url +V 79 +/private/steam/!svn/ver/3/branches/SAM/SAM.API/Interfaces/Types/UserStatType.cs +END +UserStatsStored.cs +K 25 +svn:wc:ra_dav:version-url +V 82 +/private/steam/!svn/ver/3/branches/SAM/SAM.API/Interfaces/Types/UserStatsStored.cs +END +AppDataChanged.cs +K 25 +svn:wc:ra_dav:version-url +V 81 +/private/steam/!svn/ver/3/branches/SAM/SAM.API/Interfaces/Types/AppDataChanged.cs +END +UserStatsReceived.cs +K 25 +svn:wc:ra_dav:version-url +V 84 +/private/steam/!svn/ver/3/branches/SAM/SAM.API/Interfaces/Types/UserStatsReceived.cs +END +UserItemsReceived.cs +K 25 +svn:wc:ra_dav:version-url +V 84 +/private/steam/!svn/ver/3/branches/SAM/SAM.API/Interfaces/Types/UserItemsReceived.cs +END diff --git a/SAM.API/Types/.svn/entries b/SAM.API/Types/.svn/entries new file mode 100644 index 0000000..491bd64 --- /dev/null +++ b/SAM.API/Types/.svn/entries @@ -0,0 +1,198 @@ +10 + +dir +3 +http://svn.gib.me/private/steam/branches/SAM/SAM.API/Interfaces/Types +http://svn.gib.me/private/steam + + + +2009-10-27T01:01:54.542973Z +3 +rick + + + + + + + + + + + + + + +c0897d6c-93c2-de11-ba30-0030489379b8 + +UserStatType.cs +file + + + + +2009-05-24T01:37:54.427000Z +64f89c9f38f7d18e3df59f61f593711e +2009-10-27T01:01:54.542973Z +3 +rick + + + + + + + + + + + + + + + + + + + + + +331 + +UserStatsStored.cs +file + + + + +2009-05-24T01:37:50.433000Z +11f1e7e1d5e4b4740ab9b9e42b16a00a +2009-10-27T01:01:54.542973Z +3 +rick + + + + + + + + + + + + + + + + + + + + + +377 + +AppDataChanged.cs +file + + + + +2009-05-24T01:37:09.724000Z +d6c03af98adc354940dcdbaeb4a0ddc1 +2009-10-27T01:01:54.542973Z +3 +rick + + + + + + + + + + + + + + + + + + + + + +374 + +UserStatsReceived.cs +file + + + + +2009-05-24T01:37:46.994000Z +20130d9b19a6a0532b6b4329e2d8cab3 +2009-10-27T01:01:54.542973Z +3 +rick + + + + + + + + + + + + + + + + + + + + + +379 + +UserItemsReceived.cs +file + + + + +2009-05-24T01:37:34.076000Z +e6f8773c6330b3ec861b4d4f8a4c1fbf +2009-10-27T01:01:54.542973Z +3 +rick + + + + + + + + + + + + + + + + + + + + + +343 + diff --git a/SAM.API/Types/.svn/text-base/AppDataChanged.cs.svn-base b/SAM.API/Types/.svn/text-base/AppDataChanged.cs.svn-base new file mode 100644 index 0000000..0152668 --- /dev/null +++ b/SAM.API/Types/.svn/text-base/AppDataChanged.cs.svn-base @@ -0,0 +1,14 @@ +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces.Client +{ + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct AppDataChanged + { + //[MarshalAs(UnmanagedType.U8)] + public UInt32 m_nAppID; + //[MarshalAs(UnmanagedType.I4)] + public bool m_eResult; + } +} diff --git a/SAM.API/Types/.svn/text-base/UserItemsReceived.cs.svn-base b/SAM.API/Types/.svn/text-base/UserItemsReceived.cs.svn-base new file mode 100644 index 0000000..77d6f2b --- /dev/null +++ b/SAM.API/Types/.svn/text-base/UserItemsReceived.cs.svn-base @@ -0,0 +1,13 @@ +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces.Client +{ + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct UserItemsReceived + { + public UInt64 m_nGameID; + public Int32 Unknown; // 08 + public Int32 m_nItemCount; // 0C + } +} diff --git a/SAM.API/Types/.svn/text-base/UserStatType.cs.svn-base b/SAM.API/Types/.svn/text-base/UserStatType.cs.svn-base new file mode 100644 index 0000000..980fc76 --- /dev/null +++ b/SAM.API/Types/.svn/text-base/UserStatType.cs.svn-base @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SAM.API.Interfaces.Client +{ + public enum UserStatType + { + Invalid = 0, + Integer = 1, + Float = 2, + AverageRate = 3, + Achievements = 4, + GroupAchievements = 5, + } +} diff --git a/SAM.API/Types/.svn/text-base/UserStatsReceived.cs.svn-base b/SAM.API/Types/.svn/text-base/UserStatsReceived.cs.svn-base new file mode 100644 index 0000000..559f581 --- /dev/null +++ b/SAM.API/Types/.svn/text-base/UserStatsReceived.cs.svn-base @@ -0,0 +1,14 @@ +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces.Client +{ + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct UserStatsReceived + { + //[MarshalAs(UnmanagedType.U8)] + public UInt64 m_nGameID; + //[MarshalAs(UnmanagedType.I4)] + public Int32 m_eResult; + } +} diff --git a/SAM.API/Types/.svn/text-base/UserStatsStored.cs.svn-base b/SAM.API/Types/.svn/text-base/UserStatsStored.cs.svn-base new file mode 100644 index 0000000..0355a9c --- /dev/null +++ b/SAM.API/Types/.svn/text-base/UserStatsStored.cs.svn-base @@ -0,0 +1,14 @@ +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Interfaces.Client +{ + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct UserStatsStored + { + //[MarshalAs(UnmanagedType.U8)] + public UInt64 m_nGameID; + //[MarshalAs(UnmanagedType.I4)] + public Int32 m_eResult; + } +} diff --git a/SAM.API/Types/AccountType.cs b/SAM.API/Types/AccountType.cs new file mode 100644 index 0000000..c394f42 --- /dev/null +++ b/SAM.API/Types/AccountType.cs @@ -0,0 +1,38 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.API.Types +{ + public enum AccountType : int + { + Invalid = 0, + Individual = 1, + Multiset = 2, + GameServer = 3, + AnonGameServer = 4, + Pending = 5, + ContentServer = 6, + Clan = 7, + Chat = 8, + P2PSuperSeeder = 9, + } +} diff --git a/SAM.API/Types/AppDataChanged.cs b/SAM.API/Types/AppDataChanged.cs new file mode 100644 index 0000000..d44172d --- /dev/null +++ b/SAM.API/Types/AppDataChanged.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Runtime.InteropServices; + +namespace SAM.API.Types +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AppDataChanged + { + public uint Id; + public bool Result; + } +} diff --git a/SAM.API/Types/CallbackMessage.cs b/SAM.API/Types/CallbackMessage.cs new file mode 100644 index 0000000..8bdbe4b --- /dev/null +++ b/SAM.API/Types/CallbackMessage.cs @@ -0,0 +1,36 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; + +namespace SAM.API.Types +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct CallbackMessage + { + public int User; + public int Id; + public IntPtr ParamPointer; + public int ParamSize; + } +} diff --git a/SAM.API/Types/ItemRequestResult.cs b/SAM.API/Types/ItemRequestResult.cs new file mode 100644 index 0000000..7122992 --- /dev/null +++ b/SAM.API/Types/ItemRequestResult.cs @@ -0,0 +1,37 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.API.Types +{ + public enum ItemRequestResult : int + { + InvalidValue = -1, + OK = 0, + Denied = 1, + ServerError = 2, + Timeout = 3, + Invalid = 4, + NoMatch = 5, + UnknownError = 6, + NotLoggedOn = 7, + } +} diff --git a/SAM.API/Types/UserItemsReceived.cs b/SAM.API/Types/UserItemsReceived.cs new file mode 100644 index 0000000..ea63417 --- /dev/null +++ b/SAM.API/Types/UserItemsReceived.cs @@ -0,0 +1,34 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Runtime.InteropServices; + +namespace SAM.API.Types +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UserItemsReceived + { + public ulong GameId; + public int Unknown; + public int ItemCount; + } +} diff --git a/SAM.API/Types/UserStatType.cs b/SAM.API/Types/UserStatType.cs new file mode 100644 index 0000000..e7fa519 --- /dev/null +++ b/SAM.API/Types/UserStatType.cs @@ -0,0 +1,34 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.API.Types +{ + public enum UserStatType + { + Invalid = 0, + Integer = 1, + Float = 2, + AverageRate = 3, + Achievements = 4, + GroupAchievements = 5, + } +} diff --git a/SAM.API/Types/UserStatsReceived.cs b/SAM.API/Types/UserStatsReceived.cs new file mode 100644 index 0000000..b612a06 --- /dev/null +++ b/SAM.API/Types/UserStatsReceived.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Runtime.InteropServices; + +namespace SAM.API.Types +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UserStatsReceived + { + public ulong GameId; + public int Result; + } +} diff --git a/SAM.API/Types/UserStatsStored.cs b/SAM.API/Types/UserStatsStored.cs new file mode 100644 index 0000000..646577b --- /dev/null +++ b/SAM.API/Types/UserStatsStored.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Runtime.InteropServices; + +namespace SAM.API.Types +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UserStatsStored + { + public ulong GameId; + public int Result; + } +} diff --git a/SAM.API/Wrappers/SteamApps001.cs b/SAM.API/Wrappers/SteamApps001.cs new file mode 100644 index 0000000..d82eee4 --- /dev/null +++ b/SAM.API/Wrappers/SteamApps001.cs @@ -0,0 +1,56 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using SAM.API.Interfaces; + +namespace SAM.API.Wrappers +{ + public class SteamApps001 : NativeWrapper + { + #region GetAppData + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int NativeGetAppData( + IntPtr self, + uint appId, + string key, + StringBuilder valueBuffer, + int valueLength); + + public string GetAppData(uint appId, string key) + { + var sb = new StringBuilder(); + sb.EnsureCapacity(1024); + int result = this.Call( + this.Functions.GetAppData, + this.ObjectAddress, + appId, + key, + sb, + sb.Capacity); + return result == 0 ? null : sb.ToString(); + } + #endregion + } +} diff --git a/SAM.API/Wrappers/SteamApps003.cs b/SAM.API/Wrappers/SteamApps003.cs new file mode 100644 index 0000000..fcc8b44 --- /dev/null +++ b/SAM.API/Wrappers/SteamApps003.cs @@ -0,0 +1,55 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; +using SAM.API.Interfaces; + +namespace SAM.API.Wrappers +{ + public class SteamApps003 : NativeWrapper + { + #region IsSubscribed + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeIsSubscribedApp(IntPtr self, Int64 gameId); + + public bool IsSubscribedApp(Int64 gameId) + { + return this.Call(this.Functions.IsSubscribedApp, this.ObjectAddress, gameId); + } + #endregion + + #region GetCurrentGameLanguage + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr NativeGetCurrentGameLanguage(IntPtr self); + + public string GetCurrentGameLanguage() + { + var languagePointer = this.Call( + this.Functions.GetCurrentGameLanguage, + this.ObjectAddress); + return Marshal.PtrToStringAnsi(languagePointer); + } + #endregion + } +} diff --git a/SAM.API/Wrappers/SteamClient009.cs b/SAM.API/Wrappers/SteamClient009.cs new file mode 100644 index 0000000..8f050e7 --- /dev/null +++ b/SAM.API/Wrappers/SteamClient009.cs @@ -0,0 +1,200 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; +using SAM.API.Interfaces; + +namespace SAM.API.Wrappers +{ + public class SteamClient009 : NativeWrapper + { + #region CreateSteamPipe + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int NativeCreateSteamPipe(IntPtr self); + + public int CreateSteamPipe() + { + return this.Call(this.Functions.CreateSteamPipe, this.ObjectAddress); + } + #endregion + + #region ReleaseSteamPipe + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeReleaseSteamPipe(IntPtr self); + + public bool ReleaseSteamPipe(int pipe) + { + return this.Call(this.Functions.ReleaseSteamPipe, this.ObjectAddress); + } + #endregion + + #region CreateLocalUser + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int NativeCreateLocalUser(IntPtr self, ref int pipe, Types.AccountType type); + + public int CreateLocalUser(ref int pipe, Types.AccountType type) + { + var call = this.GetFunction(this.Functions.CreateLocalUser); + return call(this.ObjectAddress, ref pipe, type); + } + #endregion + + #region ConnectToGlobalUser + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int NativeConnectToGlobalUser(IntPtr self, int pipe); + + public int ConnectToGlobalUser(int pipe) + { + return this.Call( + this.Functions.ConnectToGlobalUser, + this.ObjectAddress, + pipe); + } + #endregion + + #region ReleaseUser + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void NativeReleaseUser(IntPtr self, int pipe, int user); + + public void ReleaseUser(int pipe, int user) + { + this.Call(this.Functions.ReleaseUser, this.ObjectAddress, pipe, user); + } + #endregion + + #region SetLocalIPBinding + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void NativeSetLocalIPBinding(IntPtr self, uint host, ushort port); + + public void SetLocalIPBinding(uint host, ushort port) + { + this.Call(this.Functions.SetLocalIPBinding, this.ObjectAddress, host, port); + } + #endregion + + #region GetISteamUser + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr NativeGetISteamUser(IntPtr self, int user, int pipe, string version); + + private TClass GetISteamUser(int user, int pipe, string version) + where TClass : INativeWrapper, new() + { + IntPtr address = this.Call( + this.Functions.GetISteamUser, + this.ObjectAddress, + user, + pipe, + version); + var result = new TClass(); + result.SetupFunctions(address); + return result; + } + #endregion + + #region GetSteamUser012 + public SteamUser012 GetSteamUser012(int user, int pipe) + { + return this.GetISteamUser(user, pipe, "SteamUser012"); + } + #endregion + + #region GetISteamUserStats + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr NativeGetISteamUserStats(IntPtr self, int user, int pipe, string version); + + private TClass GetISteamUserStats(int user, int pipe, string version) + where TClass : INativeWrapper, new() + { + IntPtr address = this.Call( + this.Functions.GetISteamUserStats, + this.ObjectAddress, + user, + pipe, + version); + var result = new TClass(); + result.SetupFunctions(address); + return result; + } + #endregion + + #region GetSteamUserStats007 + public SteamUserStats007 GetSteamUserStats006(int user, int pipe) + { + return this.GetISteamUserStats(user, pipe, "STEAMUSERSTATS_INTERFACE_VERSION007"); + } + #endregion + + #region GetISteamUtils + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr NativeGetISteamUtils(IntPtr self, int pipe, string version); + + public TClass GetISteamUtils(int pipe, string version) + where TClass : INativeWrapper, new() + { + IntPtr address = this.Call( + this.Functions.GetISteamUtils, + this.ObjectAddress, + pipe, + version); + var result = new TClass(); + result.SetupFunctions(address); + return result; + } + #endregion + + #region GetSteamUtils004 + public SteamUtils005 GetSteamUtils004(int pipe) + { + return this.GetISteamUtils(pipe, "SteamUtils005"); + } + #endregion + + #region GetISteamApps + private delegate IntPtr NativeGetISteamApps(int user, int pipe, string version); + + private TClass GetISteamApps(int user, int pipe, string version) + where TClass : INativeWrapper, new() + { + IntPtr address = this.Call(this.Functions.GetISteamApps, user, pipe, version); + var result = new TClass(); + result.SetupFunctions(address); + return result; + } + #endregion + + #region GetSteamApps001 + public SteamApps001 GetSteamApps001(int user, int pipe) + { + return this.GetISteamApps(user, pipe, "STEAMAPPS_INTERFACE_VERSION001"); + } + #endregion + + #region GetSteamApps003 + public SteamApps003 GetSteamApps003(int user, int pipe) + { + return this.GetISteamApps(user, pipe, "STEAMAPPS_INTERFACE_VERSION003"); + } + #endregion + } +} diff --git a/SAM.API/Wrappers/SteamUser012.cs b/SAM.API/Wrappers/SteamUser012.cs new file mode 100644 index 0000000..c6f9afe --- /dev/null +++ b/SAM.API/Wrappers/SteamUser012.cs @@ -0,0 +1,55 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; +using SAM.API.Interfaces; + +namespace SAM.API.Wrappers +{ + public class SteamUser012 : NativeWrapper + { + #region IsLoggedIn + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeLoggedOn(IntPtr self); + + public bool IsLoggedIn() + { + return this.Call(this.Functions.LoggedOn, this.ObjectAddress); + } + #endregion + + #region GetSteamID + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void NativeGetSteamId(IntPtr self, out ulong steamId); + + public ulong GetSteamId() + { + var call = this.GetFunction(this.Functions.GetSteamID); + ulong steamId; + call(this.ObjectAddress, out steamId); + return steamId; + } + #endregion + } +} diff --git a/SAM.API/Wrappers/SteamUserStats007.cs b/SAM.API/Wrappers/SteamUserStats007.cs new file mode 100644 index 0000000..1aa91c6 --- /dev/null +++ b/SAM.API/Wrappers/SteamUserStats007.cs @@ -0,0 +1,180 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; +using SAM.API.Interfaces; + +namespace SAM.API.Wrappers +{ + public class SteamUserStats007 : NativeWrapper + { + #region RequestCurrentStats + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeRequestCurrentStats(IntPtr self); + + public bool RequestCurrentStats() + { + return this.Call(this.Functions.RequestCurrentStats, this.ObjectAddress); + } + #endregion + + #region GetStatValue (int) + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeGetStatInt(IntPtr self, string name, out int data); + + public bool GetStatValue(string name, out int value) + { + var call = this.GetFunction(this.Functions.GetStatInteger); + return call(this.ObjectAddress, name, out value); + } + #endregion + + #region GetStatValue (float) + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeGetStatFloat(IntPtr self, string name, out float data); + + public bool GetStatValue(string name, out float value) + { + var call = this.GetFunction(this.Functions.GetStatFloat); + return call(this.ObjectAddress, name, out value); + } + #endregion + + #region SetStatValue (int) + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeSetStatInt(IntPtr self, string name, int data); + + public bool SetStatValue(string name, int value) + { + return this.Call( + this.Functions.SetStatInteger, + this.ObjectAddress, + name, + value); + } + #endregion + + #region SetStatValue (float) + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeSetStatFloat(IntPtr self, string name, float data); + + public bool SetStatValue(string name, float value) + { + return this.Call( + this.Functions.SetStatFloat, + this.ObjectAddress, + name, + value); + } + #endregion + + #region GetAchievement + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeGetAchievement(IntPtr self, string name, out bool isAchieved); + + public bool GetAchievementState(string name, out bool isAchieved) + { + var call = this.GetFunction(this.Functions.GetAchievement); + return call(this.ObjectAddress, name, out isAchieved); + } + #endregion + + #region SetAchievementState + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeSetAchievement(IntPtr self, string name); + + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeClearAchievement(IntPtr self, string name); + + public bool SetAchievement(string name, bool state) + { + if (state == false) + { + return this.Call(this.Functions.ClearAchievement, this.ObjectAddress, name); + } + + return this.Call(this.Functions.SetAchievement, this.ObjectAddress, name); + } + #endregion + + #region StoreStats + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeStoreStats(IntPtr self); + + public bool StoreStats() + { + return this.Call(this.Functions.StoreStats, this.ObjectAddress); + } + #endregion + + #region GetAchievementIcon + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int NativeGetAchievementIcon(IntPtr self, string name); + + public int GetAchievementIcon(string name) + { + return this.Call( + this.Functions.GetAchievementIcon, + this.ObjectAddress, + name); + } + #endregion + + #region GetAchievementDisplayAttribute + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate string NativeGetAchievementDisplayAttribute(IntPtr self, string name, string key); + + public string GetAchievementDisplayAttribute(string name, string key) + { + return this.Call( + this.Functions.GetAchievementDisplayAttribute, + this.ObjectAddress, + name, + key); + } + #endregion + + #region ResetAllStats + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeResetAllStats(IntPtr self, bool achievementsToo); + + public bool ResetAllStats(bool achievementsToo) + { + return this.Call( + this.Functions.ResetAllStats, + this.ObjectAddress, + achievementsToo); + } + #endregion + } +} diff --git a/SAM.API/Wrappers/SteamUtils005.cs b/SAM.API/Wrappers/SteamUtils005.cs new file mode 100644 index 0000000..cded620 --- /dev/null +++ b/SAM.API/Wrappers/SteamUtils005.cs @@ -0,0 +1,85 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Runtime.InteropServices; +using SAM.API.Interfaces; + +namespace SAM.API.Wrappers +{ + public class SteamUtils005 : NativeWrapper + { + #region GetConnectedUniverse + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate int NativeGetConnectedUniverse(IntPtr self); + + public int GetConnectedUniverse() + { + return this.Call(this.Functions.GetConnectedUniverse, this.ObjectAddress); + } + #endregion + + #region GetIPCountry + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate string NativeGetIPCountry(IntPtr self); + + public string GetIPCountry() + { + return this.Call(this.Functions.GetIPCountry, this.ObjectAddress); + } + #endregion + + #region GetImageSize + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeGetImageSize(IntPtr self, int index, out int width, out int height); + + public bool GetImageSize(int index, out int width, out int height) + { + var call = this.GetFunction(this.Functions.GetImageSize); + return call(this.ObjectAddress, index, out width, out height); + } + #endregion + + #region GetImageRGBA + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + [return: MarshalAs(UnmanagedType.I1)] + private delegate bool NativeGetImageRGBA(IntPtr self, int index, byte[] buffer, int length); + + public bool GetImageRGBA(int index, byte[] data) + { + var call = this.GetFunction(this.Functions.GetImageRGBA); + return call(this.ObjectAddress, index, data, data.Length); + } + #endregion + + #region GetAppID + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate uint NativeGetAppId(IntPtr self); + + public uint GetAppId() + { + return this.Call(this.Functions.GetAppID, this.ObjectAddress); + } + #endregion + } +} diff --git a/SAM.Game/Blank.ico b/SAM.Game/Blank.ico new file mode 100644 index 0000000..f268a17 Binary files /dev/null and b/SAM.Game/Blank.ico differ diff --git a/SAM.Game/DoubleBufferedListView.cs b/SAM.Game/DoubleBufferedListView.cs new file mode 100644 index 0000000..0642c0e --- /dev/null +++ b/SAM.Game/DoubleBufferedListView.cs @@ -0,0 +1,34 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Windows.Forms; + +namespace SAM.Game +{ + internal class DoubleBufferedListView : ListView + { + public DoubleBufferedListView() + { + base.DoubleBuffered = true; + } + } +} diff --git a/SAM.Game/KeyValue.cs b/SAM.Game/KeyValue.cs new file mode 100644 index 0000000..fcabf3d --- /dev/null +++ b/SAM.Game/KeyValue.cs @@ -0,0 +1,333 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SAM.Game +{ + internal class KeyValue + { + private static readonly KeyValue _Invalid = new KeyValue(); + public string Name = ""; + public KeyValueType Type = KeyValueType.None; + public object Value; + public bool Valid; + + public List Children = null; + + public KeyValue this[string key] + { + get + { + if (this.Children == null) + { + return _Invalid; + } + + var child = this.Children.SingleOrDefault( + c => c.Name.ToLowerInvariant() == key.ToLowerInvariant()); + + if (child == null) + { + return _Invalid; + } + + return child; + } + } + + public string AsString(string defaultValue) + { + if (this.Valid == false) + { + return defaultValue; + } + + if (this.Value == null) + { + return defaultValue; + } + + return this.Value.ToString(); + } + + public int AsInteger(int defaultValue) + { + if (this.Valid == false) + { + return defaultValue; + } + + switch (this.Type) + { + case KeyValueType.String: + case KeyValueType.WideString: + { + int value; + if (int.TryParse((string)this.Value, out value) == false) + { + return defaultValue; + } + return value; + } + + case KeyValueType.Int32: + { + return (int)this.Value; + } + + case KeyValueType.Float32: + { + return (int)((float)this.Value); + } + + case KeyValueType.UInt64: + { + return (int)((ulong)this.Value & 0xFFFFFFFF); + } + } + + return defaultValue; + } + + public float AsFloat(float defaultValue) + { + if (this.Valid == false) + { + return defaultValue; + } + + switch (this.Type) + { + case KeyValueType.String: + case KeyValueType.WideString: + { + float value; + if (float.TryParse((string)this.Value, out value) == false) + { + return defaultValue; + } + return value; + } + + case KeyValueType.Int32: + { + return (int)this.Value; + } + + case KeyValueType.Float32: + { + return (float)this.Value; + } + + case KeyValueType.UInt64: + { + return (ulong)this.Value & 0xFFFFFFFF; + } + } + + return defaultValue; + } + + public bool AsBoolean(bool defaultValue) + { + if (this.Valid == false) + { + return defaultValue; + } + + switch (this.Type) + { + case KeyValueType.String: + case KeyValueType.WideString: + { + int value; + if (int.TryParse((string)this.Value, out value) == false) + { + return defaultValue; + } + return value != 0; + } + + case KeyValueType.Int32: + { + return ((int)this.Value) != 0; + } + + case KeyValueType.Float32: + { + return ((int)((float)this.Value)) != 0; + } + + case KeyValueType.UInt64: + { + return ((ulong)this.Value) != 0; + } + } + + return defaultValue; + } + + public override string ToString() + { + if (this.Valid == false) + { + return ""; + } + + if (this.Type == KeyValueType.None) + { + return this.Name; + } + + return string.Format("{0} = {1}", this.Name, this.Value); + } + + public static KeyValue LoadAsBinary(string path) + { + if (File.Exists(path) == false) + { + return null; + } + + try + { + var input = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + var kv = new KeyValue(); + + if (kv.ReadAsBinary(input) == false) + { + return null; + } + + input.Close(); + return kv; + } + catch (Exception) + { + return null; + } + } + + public bool ReadAsBinary(Stream input) + { + this.Children = new List(); + + try + { + while (true) + { + var type = (KeyValueType)input.ReadValueU8(); + + if (type == KeyValueType.End) + { + break; + } + + var current = new KeyValue + { + Type = type, + Name = input.ReadStringUnicode(), + }; + + switch (type) + { + case KeyValueType.None: + { + current.ReadAsBinary(input); + break; + } + + case KeyValueType.String: + { + current.Valid = true; + current.Value = input.ReadStringUnicode(); + break; + } + + case KeyValueType.WideString: + { + throw new FormatException("wstring is unsupported"); + } + + case KeyValueType.Int32: + { + current.Valid = true; + current.Value = input.ReadValueS32(); + break; + } + + case KeyValueType.UInt64: + { + current.Valid = true; + current.Value = input.ReadValueU64(); + break; + } + + case KeyValueType.Float32: + { + current.Valid = true; + current.Value = input.ReadValueF32(); + break; + } + + case KeyValueType.Color: + { + current.Valid = true; + current.Value = input.ReadValueU32(); + break; + } + + case KeyValueType.Pointer: + { + current.Valid = true; + current.Value = input.ReadValueU32(); + break; + } + + default: + { + throw new FormatException(); + } + } + + if (input.Position >= input.Length) + { + throw new FormatException(); + } + + this.Children.Add(current); + } + + this.Valid = true; + return input.Position == input.Length; + } + catch (Exception) + { + return false; + } + } + } +} diff --git a/SAM.Game/KeyValueType.cs b/SAM.Game/KeyValueType.cs new file mode 100644 index 0000000..7e6645d --- /dev/null +++ b/SAM.Game/KeyValueType.cs @@ -0,0 +1,37 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game +{ + internal enum KeyValueType : byte + { + None = 0, + String = 1, + Int32 = 2, + Float32 = 3, + Pointer = 4, + WideString = 5, + Color = 6, + UInt64 = 7, + End = 8, + } +} diff --git a/SAM.Game/LICENSE.txt b/SAM.Game/LICENSE.txt new file mode 100644 index 0000000..43d0120 --- /dev/null +++ b/SAM.Game/LICENSE.txt @@ -0,0 +1,22 @@ +zlib License + +Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. \ No newline at end of file diff --git a/SAM.Game/Manager.Designer.cs b/SAM.Game/Manager.Designer.cs new file mode 100644 index 0000000..ff2b118 --- /dev/null +++ b/SAM.Game/Manager.Designer.cs @@ -0,0 +1,359 @@ +namespace SAM.Game +{ + partial class Manager + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.ToolStripSeparator _ToolStripSeparator1; + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Manager)); + this._MainToolStrip = new System.Windows.Forms.ToolStrip(); + this._StoreButton = new System.Windows.Forms.ToolStripButton(); + this._ReloadButton = new System.Windows.Forms.ToolStripButton(); + this._ResetButton = new System.Windows.Forms.ToolStripButton(); + this._AchievementImageList = new System.Windows.Forms.ImageList(this.components); + this._MainStatusStrip = new System.Windows.Forms.StatusStrip(); + this._CountryStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this._GameStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this._DownloadStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this._CallbackTimer = new System.Windows.Forms.Timer(this.components); + this._MainTabControl = new System.Windows.Forms.TabControl(); + this._AchievementsTabPage = new System.Windows.Forms.TabPage(); + this._AchievementListView = new SAM.Game.DoubleBufferedListView(); + this._AchievementNameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this._AchievementDescriptionColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this._AchievementsToolStrip = new System.Windows.Forms.ToolStrip(); + this._LockAllButton = new System.Windows.Forms.ToolStripButton(); + this._InvertAllButton = new System.Windows.Forms.ToolStripButton(); + this._UnlockAllButton = new System.Windows.Forms.ToolStripButton(); + this._StatisticsTabPage = new System.Windows.Forms.TabPage(); + this._EnableStatsEditingCheckBox = new System.Windows.Forms.CheckBox(); + this._StatisticsDataGridView = new System.Windows.Forms.DataGridView(); + _ToolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this._MainToolStrip.SuspendLayout(); + this._MainStatusStrip.SuspendLayout(); + this._MainTabControl.SuspendLayout(); + this._AchievementsTabPage.SuspendLayout(); + this._AchievementsToolStrip.SuspendLayout(); + this._StatisticsTabPage.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this._StatisticsDataGridView)).BeginInit(); + this.SuspendLayout(); + // + // _MainToolStrip + // + this._MainToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this._StoreButton, + this._ReloadButton, + _ToolStripSeparator1, + this._ResetButton}); + this._MainToolStrip.Location = new System.Drawing.Point(0, 0); + this._MainToolStrip.Name = "_MainToolStrip"; + this._MainToolStrip.Size = new System.Drawing.Size(632, 25); + this._MainToolStrip.TabIndex = 1; + // + // _StoreButton + // + this._StoreButton.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this._StoreButton.Enabled = false; + this._StoreButton.Image = global::SAM.Game.Properties.Resources.Save; + this._StoreButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._StoreButton.Name = "_StoreButton"; + this._StoreButton.Size = new System.Drawing.Size(54, 22); + this._StoreButton.Text = "Store"; + this._StoreButton.ToolTipText = "Store achievements and statistics for active game."; + this._StoreButton.Click += new System.EventHandler(this.OnStore); + // + // _ReloadButton + // + this._ReloadButton.Enabled = false; + this._ReloadButton.Image = global::SAM.Game.Properties.Resources.Refresh; + this._ReloadButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._ReloadButton.Name = "_ReloadButton"; + this._ReloadButton.Size = new System.Drawing.Size(66, 22); + this._ReloadButton.Text = "Refresh"; + this._ReloadButton.ToolTipText = "Refresh achievements and statistics for active game."; + this._ReloadButton.Click += new System.EventHandler(this.OnRefresh); + // + // _ToolStripSeparator1 + // + _ToolStripSeparator1.Name = "_ToolStripSeparator1"; + _ToolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // + // _ResetButton + // + this._ResetButton.Image = global::SAM.Game.Properties.Resources.Reset; + this._ResetButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._ResetButton.Name = "_ResetButton"; + this._ResetButton.Size = new System.Drawing.Size(55, 22); + this._ResetButton.Text = "Reset"; + this._ResetButton.ToolTipText = "Reset achievements and/or statistics for active game."; + this._ResetButton.Click += new System.EventHandler(this.OnResetAllStats); + // + // _AchievementImageList + // + this._AchievementImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit; + this._AchievementImageList.ImageSize = new System.Drawing.Size(64, 64); + this._AchievementImageList.TransparentColor = System.Drawing.Color.Transparent; + // + // _MainStatusStrip + // + this._MainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this._CountryStatusLabel, + this._GameStatusLabel, + this._DownloadStatusLabel}); + this._MainStatusStrip.Location = new System.Drawing.Point(0, 370); + this._MainStatusStrip.Name = "_MainStatusStrip"; + this._MainStatusStrip.Size = new System.Drawing.Size(632, 22); + this._MainStatusStrip.TabIndex = 4; + this._MainStatusStrip.Text = "statusStrip1"; + // + // _CountryStatusLabel + // + this._CountryStatusLabel.Name = "_CountryStatusLabel"; + this._CountryStatusLabel.Size = new System.Drawing.Size(0, 17); + // + // _GameStatusLabel + // + this._GameStatusLabel.Name = "_GameStatusLabel"; + this._GameStatusLabel.Size = new System.Drawing.Size(617, 17); + this._GameStatusLabel.Spring = true; + this._GameStatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // _DownloadStatusLabel + // + this._DownloadStatusLabel.Image = global::SAM.Game.Properties.Resources.Download; + this._DownloadStatusLabel.Name = "_DownloadStatusLabel"; + this._DownloadStatusLabel.Size = new System.Drawing.Size(111, 17); + this._DownloadStatusLabel.Text = "Download status"; + this._DownloadStatusLabel.Visible = false; + // + // _CallbackTimer + // + this._CallbackTimer.Enabled = true; + this._CallbackTimer.Tick += new System.EventHandler(this.OnTimer); + // + // _MainTabControl + // + this._MainTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._MainTabControl.Controls.Add(this._AchievementsTabPage); + this._MainTabControl.Controls.Add(this._StatisticsTabPage); + this._MainTabControl.Location = new System.Drawing.Point(8, 33); + this._MainTabControl.Name = "_MainTabControl"; + this._MainTabControl.SelectedIndex = 0; + this._MainTabControl.Size = new System.Drawing.Size(616, 334); + this._MainTabControl.TabIndex = 5; + // + // _AchievementsTabPage + // + this._AchievementsTabPage.Controls.Add(this._AchievementListView); + this._AchievementsTabPage.Controls.Add(this._AchievementsToolStrip); + this._AchievementsTabPage.Location = new System.Drawing.Point(4, 22); + this._AchievementsTabPage.Name = "_AchievementsTabPage"; + this._AchievementsTabPage.Padding = new System.Windows.Forms.Padding(3); + this._AchievementsTabPage.Size = new System.Drawing.Size(608, 308); + this._AchievementsTabPage.TabIndex = 0; + this._AchievementsTabPage.Text = "Achievements"; + this._AchievementsTabPage.UseVisualStyleBackColor = true; + // + // _AchievementListView + // + this._AchievementListView.Activation = System.Windows.Forms.ItemActivation.OneClick; + this._AchievementListView.BackColor = System.Drawing.Color.Black; + this._AchievementListView.BackgroundImageTiled = true; + this._AchievementListView.CheckBoxes = true; + this._AchievementListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this._AchievementNameColumnHeader, + this._AchievementDescriptionColumnHeader}); + this._AchievementListView.Dock = System.Windows.Forms.DockStyle.Fill; + this._AchievementListView.ForeColor = System.Drawing.Color.White; + this._AchievementListView.FullRowSelect = true; + this._AchievementListView.GridLines = true; + this._AchievementListView.HideSelection = false; + this._AchievementListView.LargeImageList = this._AchievementImageList; + this._AchievementListView.Location = new System.Drawing.Point(3, 28); + this._AchievementListView.Name = "_AchievementListView"; + this._AchievementListView.Size = new System.Drawing.Size(602, 277); + this._AchievementListView.SmallImageList = this._AchievementImageList; + this._AchievementListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + this._AchievementListView.TabIndex = 4; + this._AchievementListView.UseCompatibleStateImageBehavior = false; + this._AchievementListView.View = System.Windows.Forms.View.Details; + this._AchievementListView.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.OnCheckAchievement); + // + // _AchievementNameColumnHeader + // + this._AchievementNameColumnHeader.Text = "Name"; + this._AchievementNameColumnHeader.Width = 200; + // + // _AchievementDescriptionColumnHeader + // + this._AchievementDescriptionColumnHeader.Text = "Description"; + this._AchievementDescriptionColumnHeader.Width = 380; + // + // _AchievementsToolStrip + // + this._AchievementsToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this._LockAllButton, + this._InvertAllButton, + this._UnlockAllButton}); + this._AchievementsToolStrip.Location = new System.Drawing.Point(3, 3); + this._AchievementsToolStrip.Name = "_AchievementsToolStrip"; + this._AchievementsToolStrip.Size = new System.Drawing.Size(602, 25); + this._AchievementsToolStrip.TabIndex = 5; + // + // _LockAllButton + // + this._LockAllButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this._LockAllButton.Image = global::SAM.Game.Properties.Resources.Lock; + this._LockAllButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._LockAllButton.Name = "_LockAllButton"; + this._LockAllButton.Size = new System.Drawing.Size(23, 22); + this._LockAllButton.Text = "Lock All"; + this._LockAllButton.ToolTipText = "Lock all achievements."; + this._LockAllButton.Click += new System.EventHandler(this.OnLockAll); + // + // _InvertAllButton + // + this._InvertAllButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this._InvertAllButton.Image = global::SAM.Game.Properties.Resources.Invert; + this._InvertAllButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._InvertAllButton.Name = "_InvertAllButton"; + this._InvertAllButton.Size = new System.Drawing.Size(23, 22); + this._InvertAllButton.Text = "Invert All"; + this._InvertAllButton.ToolTipText = "Invert all achievements."; + this._InvertAllButton.Click += new System.EventHandler(this.OnInvertAll); + // + // _UnlockAllButton + // + this._UnlockAllButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this._UnlockAllButton.Image = global::SAM.Game.Properties.Resources.Unlock; + this._UnlockAllButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._UnlockAllButton.Name = "_UnlockAllButton"; + this._UnlockAllButton.Size = new System.Drawing.Size(23, 22); + this._UnlockAllButton.Text = "Unlock All"; + this._UnlockAllButton.ToolTipText = "Unlock all achievements."; + this._UnlockAllButton.Click += new System.EventHandler(this.OnUnlockAll); + // + // _StatisticsTabPage + // + this._StatisticsTabPage.Controls.Add(this._EnableStatsEditingCheckBox); + this._StatisticsTabPage.Controls.Add(this._StatisticsDataGridView); + this._StatisticsTabPage.Location = new System.Drawing.Point(4, 22); + this._StatisticsTabPage.Name = "_StatisticsTabPage"; + this._StatisticsTabPage.Padding = new System.Windows.Forms.Padding(3); + this._StatisticsTabPage.Size = new System.Drawing.Size(608, 308); + this._StatisticsTabPage.TabIndex = 1; + this._StatisticsTabPage.Text = "Statistics"; + this._StatisticsTabPage.UseVisualStyleBackColor = true; + // + // _EnableStatsEditingCheckBox + // + this._EnableStatsEditingCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._EnableStatsEditingCheckBox.AutoSize = true; + this._EnableStatsEditingCheckBox.Location = new System.Drawing.Point(6, 285); + this._EnableStatsEditingCheckBox.Name = "_EnableStatsEditingCheckBox"; + this._EnableStatsEditingCheckBox.Size = new System.Drawing.Size(512, 17); + this._EnableStatsEditingCheckBox.TabIndex = 1; + this._EnableStatsEditingCheckBox.Text = "I understand by modifying the values of stats, I may screw things up and can\'t bl" + + "ame anyone but myself."; + this._EnableStatsEditingCheckBox.UseVisualStyleBackColor = true; + this._EnableStatsEditingCheckBox.CheckedChanged += new System.EventHandler(this.OnStatAgreementChecked); + // + // _StatisticsDataGridView + // + this._StatisticsDataGridView.AllowUserToAddRows = false; + this._StatisticsDataGridView.AllowUserToDeleteRows = false; + this._StatisticsDataGridView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this._StatisticsDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this._StatisticsDataGridView.Location = new System.Drawing.Point(6, 6); + this._StatisticsDataGridView.Name = "_StatisticsDataGridView"; + this._StatisticsDataGridView.Size = new System.Drawing.Size(596, 273); + this._StatisticsDataGridView.TabIndex = 0; + this._StatisticsDataGridView.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.OnStatCellEndEdit); + this._StatisticsDataGridView.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.OnStatDataError); + // + // Manager + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(632, 392); + this.Controls.Add(this._MainToolStrip); + this.Controls.Add(this._MainTabControl); + this.Controls.Add(this._MainStatusStrip); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(640, 50); + this.Name = "Manager"; + this.Text = "Steam Achievement Manager 6.3"; + this._MainToolStrip.ResumeLayout(false); + this._MainToolStrip.PerformLayout(); + this._MainStatusStrip.ResumeLayout(false); + this._MainStatusStrip.PerformLayout(); + this._MainTabControl.ResumeLayout(false); + this._AchievementsTabPage.ResumeLayout(false); + this._AchievementsTabPage.PerformLayout(); + this._AchievementsToolStrip.ResumeLayout(false); + this._AchievementsToolStrip.PerformLayout(); + this._StatisticsTabPage.ResumeLayout(false); + this._StatisticsTabPage.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this._StatisticsDataGridView)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ToolStrip _MainToolStrip; + private System.Windows.Forms.ToolStripButton _StoreButton; + private System.Windows.Forms.ToolStripButton _ReloadButton; + private System.Windows.Forms.StatusStrip _MainStatusStrip; + private System.Windows.Forms.ToolStripStatusLabel _CountryStatusLabel; + private System.Windows.Forms.ToolStripStatusLabel _GameStatusLabel; + private System.Windows.Forms.ImageList _AchievementImageList; + private System.Windows.Forms.Timer _CallbackTimer; + private System.Windows.Forms.TabControl _MainTabControl; + private System.Windows.Forms.TabPage _AchievementsTabPage; + private System.Windows.Forms.TabPage _StatisticsTabPage; + private DoubleBufferedListView _AchievementListView; + private System.Windows.Forms.ColumnHeader _AchievementNameColumnHeader; + private System.Windows.Forms.ColumnHeader _AchievementDescriptionColumnHeader; + private System.Windows.Forms.ToolStrip _AchievementsToolStrip; + private System.Windows.Forms.ToolStripButton _LockAllButton; + private System.Windows.Forms.ToolStripButton _InvertAllButton; + private System.Windows.Forms.ToolStripButton _UnlockAllButton; + private System.Windows.Forms.DataGridView _StatisticsDataGridView; + public System.Windows.Forms.CheckBox _EnableStatsEditingCheckBox; + private System.Windows.Forms.ToolStripButton _ResetButton; + private System.Windows.Forms.ToolStripStatusLabel _DownloadStatusLabel; + } +} + diff --git a/SAM.Game/Manager.cs b/SAM.Game/Manager.cs new file mode 100644 index 0000000..50f501e --- /dev/null +++ b/SAM.Game/Manager.cs @@ -0,0 +1,843 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Windows.Forms; +using APITypes = SAM.API.Types; + +namespace SAM.Game +{ + internal partial class Manager : Form + { + private readonly long _GameId; + private readonly API.Client _SteamClient; + + private readonly WebClient _IconDownloader = new WebClient(); + + private readonly List _IconQueue = new List(); + private readonly List _StatDefinitions = new List(); + + private readonly List _AchievementDefinitions = + new List(); + + private readonly BindingList _Statistics = new BindingList(); + + // ReSharper disable PrivateFieldCanBeConvertedToLocalVariable + private readonly API.Callbacks.UserStatsReceived _UserStatsReceivedCallback; + // ReSharper restore PrivateFieldCanBeConvertedToLocalVariable + + //private API.Callback UserStatsStoredCallback; + + public Manager(long gameId, API.Client client) + { + this.InitializeComponent(); + + this._MainTabControl.SelectedTab = this._AchievementsTabPage; + //this.statisticsList.Enabled = this.checkBox1.Checked; + + this._AchievementImageList.Images.Add("Blank", new Bitmap(64, 64)); + + this._StatisticsDataGridView.AutoGenerateColumns = false; + + this._StatisticsDataGridView.Columns.Add("name", "Name"); + this._StatisticsDataGridView.Columns[0].ReadOnly = true; + this._StatisticsDataGridView.Columns[0].Width = 200; + this._StatisticsDataGridView.Columns[0].DataPropertyName = "DisplayName"; + + this._StatisticsDataGridView.Columns.Add("value", "Value"); + this._StatisticsDataGridView.Columns[1].ReadOnly = this._EnableStatsEditingCheckBox.Checked == false; + this._StatisticsDataGridView.Columns[1].Width = 90; + this._StatisticsDataGridView.Columns[1].DataPropertyName = "Value"; + + this._StatisticsDataGridView.Columns.Add("extra", "Extra"); + this._StatisticsDataGridView.Columns[2].ReadOnly = true; + this._StatisticsDataGridView.Columns[2].Width = 200; + this._StatisticsDataGridView.Columns[2].DataPropertyName = "Extra"; + + this._StatisticsDataGridView.DataSource = new BindingSource + { + DataSource = this._Statistics, + }; + + this._GameId = gameId; + this._SteamClient = client; + + this._IconDownloader.DownloadDataCompleted += this.OnIconDownload; + + string name = this._SteamClient.SteamApps001.GetAppData((uint)this._GameId, "name"); + if (name != null) + { + base.Text += " | " + name; + } + else + { + base.Text += " | " + this._GameId.ToString(CultureInfo.InvariantCulture); + } + + this._UserStatsReceivedCallback = client.CreateAndRegisterCallback(); + this._UserStatsReceivedCallback.OnRun += this.OnUserStatsReceived; + + //this.UserStatsStoredCallback = new API.Callback(1102, new API.Callback.CallbackFunction(this.OnUserStatsStored)); + this.RefreshStats(); + } + + private void AddAchievementIcon(Stats.AchievementInfo info, Image icon) + { + if (icon == null) + { + info.ImageIndex = 0; + } + else + { + info.ImageIndex = this._AchievementImageList.Images.Count; + this._AchievementImageList.Images.Add(info.IsAchieved == true ? info.IconNormal : info.IconLocked, icon); + } + } + + private void OnIconDownload(object sender, DownloadDataCompletedEventArgs e) + { + if (e.Error == null && e.Cancelled == false) + { + var info = e.UserState as Stats.AchievementInfo; + + Bitmap bitmap; + + try + { + using (var stream = new MemoryStream()) + { + stream.Write(e.Result, 0, e.Result.Length); + bitmap = new Bitmap(stream); + } + } + catch (Exception) + { + bitmap = null; + } + + this.AddAchievementIcon(info, bitmap); + this._AchievementListView.Update(); + } + + this.DownloadNextIcon(); + } + + private void DownloadNextIcon() + { + if (this._IconQueue.Count == 0) + { + this._DownloadStatusLabel.Visible = false; + return; + } + + if (this._IconDownloader.IsBusy) + { + return; + } + + this._DownloadStatusLabel.Text = string.Format("Downloading {0} icons...", this._IconQueue.Count); + this._DownloadStatusLabel.Visible = true; + + var info = this._IconQueue[0]; + this._IconQueue.RemoveAt(0); + + + this._IconDownloader.DownloadDataAsync( + new Uri(string.Format("http://media.steamcommunity.com/steamcommunity/public/images/apps/{0}/{1}", + this._GameId, + info.IsAchieved == true ? info.IconNormal : info.IconLocked)), + info); + } + + private string TranslateError(int id) + { + switch (id) + { + case 2: + { + return "generic error -- this usually means you don't own the game"; + } + } + + return id.ToString(CultureInfo.InvariantCulture); + } + + private string GetLocalizedString(KeyValue kv, string language, string defaultValue) + { + var name = kv[language].AsString(""); + if (string.IsNullOrEmpty(name) == false) + { + return name; + } + + if (language != "english") + { + name = kv["english"].AsString(""); + if (string.IsNullOrEmpty(name) == false) + { + return name; + } + } + + name = kv.AsString(""); + if (string.IsNullOrEmpty(name) == false) + { + return name; + } + + return defaultValue; + } + + private bool LoadUserGameStatsSchema() + { + string path; + + try + { + path = API.Steam.GetInstallPath(); + path = Path.Combine(path, "appcache"); + path = Path.Combine(path, "stats"); + path = Path.Combine(path, string.Format("UserGameStatsSchema_{0}.bin", this._GameId)); + + if (File.Exists(path) == false) + { + return false; + } + } + catch + { + return false; + } + + var kv = KeyValue.LoadAsBinary(path); + + if (kv == null) + { + return false; + } + + var currentLanguage = this._SteamClient.SteamApps003.GetCurrentGameLanguage(); + //var currentLanguage = "german"; + + this._AchievementDefinitions.Clear(); + this._StatDefinitions.Clear(); + + var stats = kv[this._GameId.ToString(CultureInfo.InvariantCulture)]["stats"]; + if (stats.Valid == false || + stats.Children == null) + { + return false; + } + + foreach (var stat in stats.Children) + { + if (stat.Valid == false) + { + continue; + } + + var rawType = stat["type_int"].Valid + ? stat["type_int"].AsInteger(0) + : stat["type"].AsInteger(0); + var type = (APITypes.UserStatType)rawType; + switch (type) + { + case API.Types.UserStatType.Invalid: + { + break; + } + + case APITypes.UserStatType.Integer: + { + var id = stat["name"].AsString(""); + string name = GetLocalizedString(stat["display"]["name"], currentLanguage, id); + + this._StatDefinitions.Add(new Stats.IntegerStatDefinition() + { + Id = stat["name"].AsString(""), + DisplayName = name, + MinValue = stat["min"].AsInteger(int.MinValue), + MaxValue = stat["max"].AsInteger(int.MaxValue), + MaxChange = stat["maxchange"].AsInteger(0), + IncrementOnly = stat["incrementonly"].AsBoolean(false), + DefaultValue = stat["default"].AsInteger(0), + Permission = stat["permission"].AsInteger(0), + }); + break; + } + + case APITypes.UserStatType.Float: + case APITypes.UserStatType.AverageRate: + { + var id = stat["name"].AsString(""); + string name = GetLocalizedString(stat["display"]["name"], currentLanguage, id); + + this._StatDefinitions.Add(new Stats.FloatStatDefinition() + { + Id = stat["name"].AsString(""), + DisplayName = name, + MinValue = stat["min"].AsFloat(float.MinValue), + MaxValue = stat["max"].AsFloat(float.MaxValue), + MaxChange = stat["maxchange"].AsFloat(0.0f), + IncrementOnly = stat["incrementonly"].AsBoolean(false), + DefaultValue = stat["default"].AsFloat(0.0f), + Permission = stat["permission"].AsInteger(0), + }); + break; + } + + case APITypes.UserStatType.Achievements: + case APITypes.UserStatType.GroupAchievements: + { + if (stat.Children != null) + { + foreach (var bits in stat.Children.Where( + b => b.Name.ToLowerInvariant() == "bits")) + { + if (bits.Valid == false || + bits.Children == null) + { + continue; + } + + foreach (var bit in bits.Children) + { + string id = bit["name"].AsString(""); + string name = GetLocalizedString(bit["display"]["name"], currentLanguage, id); + string desc = GetLocalizedString(bit["display"]["desc"], currentLanguage, ""); + + this._AchievementDefinitions.Add(new Stats.AchievementDefinition() + { + Id = id, + Name = name, + Description = desc, + IconNormal = bit["display"]["icon"].AsString(""), + IconLocked = bit["display"]["icon_gray"].AsString(""), + IsHidden = bit["display"]["hidden"].AsBoolean(false), + Permission = bit["permission"].AsInteger(0), + }); + } + } + } + + break; + } + + default: + { + throw new InvalidOperationException("invalid stat type"); + } + } + } + + return true; + } + + private void OnUserStatsReceived(APITypes.UserStatsReceived param) + { + if (param.Result != 1) + { + this._GameStatusLabel.Text = string.Format( + "Error while retrieving stats: {0}", + TranslateError(param.Result)); + this.EnableInput(); + return; + } + + if (this.LoadUserGameStatsSchema() == false) + { + this._GameStatusLabel.Text = "Failed to load schema."; + this.EnableInput(); + return; + } + + try + { + this.GetAchievements(); + this.GetStatistics(); + } + catch (Exception e) + { + this._GameStatusLabel.Text = "Error when handling stats retrieval."; + this.EnableInput(); + MessageBox.Show( + "Error when handling stats retrieval:\n" + e, + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + this._GameStatusLabel.Text = string.Format( + "Retrieved {0} achievements and {1} statistics.", + this._AchievementListView.Items.Count, + this._StatisticsDataGridView.Rows.Count); + this.EnableInput(); + } + + private void RefreshStats() + { + this._AchievementListView.Items.Clear(); + this._StatisticsDataGridView.Rows.Clear(); + + if (this._SteamClient.SteamUserStats.RequestCurrentStats() == false) + { + MessageBox.Show(this, "Failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this._GameStatusLabel.Text = "Retrieving stat information..."; + this.DisableInput(); + } + + private bool _IsUpdatingAchievementList; + + private void GetAchievements() + { + this._IsUpdatingAchievementList = true; + + this._AchievementListView.Items.Clear(); + this._AchievementListView.BeginUpdate(); + //this.Achievements.Clear(); + + foreach (var def in this._AchievementDefinitions) + { + if (def.Id == string.Empty) + { + continue; + } + + bool isAchieved; + if (this._SteamClient.SteamUserStats.GetAchievementState(def.Id, out isAchieved) == false) + { + continue; + } + + var info = new Stats.AchievementInfo() + { + Id = def.Id, + IsAchieved = isAchieved, + IconNormal = string.IsNullOrEmpty(def.IconNormal) ? null : def.IconNormal, + IconLocked = string.IsNullOrEmpty(def.IconLocked) ? def.IconNormal : def.IconLocked, + Permission = def.Permission, + Name = def.Name, + Description = def.Description, + }; + + var item = new ListViewItem() + { + Checked = isAchieved, + Tag = info, + Text = info.Name, + BackColor = (def.Permission & 2) == 0 ? Color.Black : Color.FromArgb(64, 0, 0), + }; + + info.Item = item; + + if (item.Text.StartsWith("#") == true) + { + item.Text = info.Id; + } + else + { + item.SubItems.Add(info.Description); + } + + info.ImageIndex = 0; + + this.AddAchievementToIconQueue(info, false); + this._AchievementListView.Items.Add(item); + //this.Achievements.Add(info.Id, info); + } + this._AchievementListView.EndUpdate(); + this._IsUpdatingAchievementList = false; + + this.DownloadNextIcon(); + } + + private void GetStatistics() + { + this._Statistics.Clear(); + foreach (var rdef in this._StatDefinitions) + { + if (string.IsNullOrEmpty(rdef.Id) == true) + { + continue; + } + + if (rdef is Stats.IntegerStatDefinition) + { + var def = (Stats.IntegerStatDefinition)rdef; + + int value; + if (this._SteamClient.SteamUserStats.GetStatValue(def.Id, out value)) + { + this._Statistics.Add(new Stats.IntStatInfo() + { + Id = def.Id, + DisplayName = def.DisplayName, + IntValue = value, + OriginalValue = value, + IsIncrementOnly = def.IncrementOnly, + Permission = def.Permission, + }); + } + } + else if (rdef is Stats.FloatStatDefinition) + { + var def = (Stats.FloatStatDefinition)rdef; + + float value; + if (this._SteamClient.SteamUserStats.GetStatValue(def.Id, out value)) + { + this._Statistics.Add(new Stats.FloatStatInfo() + { + Id = def.Id, + DisplayName = def.DisplayName, + FloatValue = value, + OriginalValue = value, + IsIncrementOnly = def.IncrementOnly, + Permission = def.Permission, + }); + } + } + } + } + + private void AddAchievementToIconQueue(Stats.AchievementInfo info, bool startDownload) + { + int imageIndex = this._AchievementImageList.Images.IndexOfKey( + info.IsAchieved == true ? info.IconNormal : info.IconLocked); + + if (imageIndex >= 0) + { + info.ImageIndex = imageIndex; + } + else + { + this._IconQueue.Add(info); + + if (startDownload == true) + { + this.DownloadNextIcon(); + } + } + } + + private int StoreAchievements() + { + if (this._AchievementListView.Items.Count == 0) + { + return 0; + } + + var achievements = new List(); + foreach (ListViewItem item in this._AchievementListView.Items) + { + var achievementInfo = item.Tag as Stats.AchievementInfo; + if (achievementInfo != null && + achievementInfo.IsAchieved != item.Checked) + { + achievementInfo.IsAchieved = item.Checked; + achievements.Add(item.Tag as Stats.AchievementInfo); + } + } + + if (achievements.Count == 0) + { + return 0; + } + + foreach (Stats.AchievementInfo info in achievements) + { + if (this._SteamClient.SteamUserStats.SetAchievement(info.Id, info.IsAchieved) == false) + { + MessageBox.Show( + this, + string.Format("An error occured while setting the state for {0}, aborting store.", info.Id), + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return -1; + } + } + + return achievements.Count; + } + + private int StoreStatistics() + { + if (this._Statistics.Count == 0) + { + return 0; + } + + var statistics = this._Statistics.Where(stat => stat.IsModified == true).ToList(); + if (statistics.Count == 0) + { + return 0; + } + + foreach (Stats.StatInfo stat in statistics) + { + if (stat is Stats.IntStatInfo) + { + var intStat = (Stats.IntStatInfo)stat; + if (this._SteamClient.SteamUserStats.SetStatValue( + intStat.Id, + intStat.IntValue) == false) + { + MessageBox.Show( + this, + string.Format("An error occured while setting the value for {0}, aborting store.", stat.Id), + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return -1; + } + } + else if (stat is Stats.FloatStatInfo) + { + var floatStat = (Stats.FloatStatInfo)stat; + if (this._SteamClient.SteamUserStats.SetStatValue( + floatStat.Id, + floatStat.FloatValue) == false) + { + MessageBox.Show( + this, + string.Format("An error occured while setting the value for {0}, aborting store.", stat.Id), + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return -1; + } + } + else + { + throw new Exception(); + } + } + + return statistics.Count; + } + + private void DisableInput() + { + this._ReloadButton.Enabled = false; + this._StoreButton.Enabled = false; + } + + private void EnableInput() + { + this._ReloadButton.Enabled = true; + this._StoreButton.Enabled = true; + } + + private void OnTimer(object sender, EventArgs e) + { + this._CallbackTimer.Enabled = false; + this._SteamClient.RunCallbacks(false); + this._CallbackTimer.Enabled = true; + } + + private void OnRefresh(object sender, EventArgs e) + { + this.RefreshStats(); + } + + private void OnLockAll(object sender, EventArgs e) + { + foreach (ListViewItem item in this._AchievementListView.Items) + { + item.Checked = false; + } + } + + private void OnInvertAll(object sender, EventArgs e) + { + foreach (ListViewItem item in this._AchievementListView.Items) + { + item.Checked = !item.Checked; + } + } + + private void OnUnlockAll(object sender, EventArgs e) + { + foreach (ListViewItem item in this._AchievementListView.Items) + { + item.Checked = true; + } + } + + private bool Store() + { + if (this._SteamClient.SteamUserStats.StoreStats() == false) + { + MessageBox.Show( + this, + "An error occured while storing, aborting.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return false; + } + + return true; + } + + private void OnStore(object sender, EventArgs e) + { + int achievements = this.StoreAchievements(); + if (achievements < 0) + { + this.RefreshStats(); + return; + } + + int stats = this.StoreStatistics(); + if (stats < 0) + { + this.RefreshStats(); + return; + } + + if (this.Store() == false) + { + this.RefreshStats(); + return; + } + + MessageBox.Show( + this, + string.Format("Stored {0} achievements and {1} statistics.", achievements, stats), + "Information", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + this.RefreshStats(); + } + + private void OnStatDataError(object sender, DataGridViewDataErrorEventArgs e) + { + if (e.Context == DataGridViewDataErrorContexts.Commit) + { + if (e.Exception is Stats.StatIsProtectedException) + { + e.ThrowException = false; + e.Cancel = true; + var view = (DataGridView)sender; + view.Rows[e.RowIndex].ErrorText = "Stat is protected! -- you can't modify it"; + } + else + { + e.ThrowException = false; + e.Cancel = true; + var view = (DataGridView)sender; + view.Rows[e.RowIndex].ErrorText = "Invalid value"; + } + } + } + + private void OnStatAgreementChecked(object sender, EventArgs e) + { + this._StatisticsDataGridView.Columns[1].ReadOnly = this._EnableStatsEditingCheckBox.Checked == false; + } + + private void OnStatCellEndEdit(object sender, DataGridViewCellEventArgs e) + { + var view = (DataGridView)sender; + view.Rows[e.RowIndex].ErrorText = ""; + } + + private void OnResetAllStats(object sender, EventArgs e) + { + if (MessageBox.Show( + "Are you absolutely sure you want to reset stats?", + "Warning", + MessageBoxButtons.YesNo, + MessageBoxIcon.Warning) == DialogResult.No) + { + return; + } + + bool achievementsToo = DialogResult.Yes == MessageBox.Show( + "Do you want to reset achievements too?", + "Question", + MessageBoxButtons.YesNo, + MessageBoxIcon.Question); + + if (MessageBox.Show( + "Really really sure?", + "Warning", + MessageBoxButtons.YesNo, + MessageBoxIcon.Error) == DialogResult.No) + { + return; + } + + if (this._SteamClient.SteamUserStats.ResetAllStats(achievementsToo) == false) + { + MessageBox.Show(this, "Failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this.RefreshStats(); + } + + private void OnCheckAchievement(object sender, ItemCheckEventArgs e) + { + if (sender != this._AchievementListView) + { + return; + } + + if (this._IsUpdatingAchievementList == true) + { + return; + } + + var info = this._AchievementListView.Items[e.Index].Tag + as Stats.AchievementInfo; + if (info == null) + { + return; + } + + if ((info.Permission & 2) != 0) + { + MessageBox.Show( + this, + "Sorry, but this is a protected achievement and cannot be managed with Steam Achievement Manager.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + e.NewValue = e.CurrentValue; + } + } + } +} diff --git a/SAM.Game/Manager.resx b/SAM.Game/Manager.resx new file mode 100644 index 0000000..0a5f39e --- /dev/null +++ b/SAM.Game/Manager.resx @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + False + + + 352, 20 + + + 230, 17 + + + 502, 20 + + + 628, 20 + + + + + AAABAAEAEBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADAgP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA + + + \ No newline at end of file diff --git a/SAM.Game/Program.cs b/SAM.Game/Program.cs new file mode 100644 index 0000000..bc3f5de --- /dev/null +++ b/SAM.Game/Program.cs @@ -0,0 +1,92 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Diagnostics; +using System.Windows.Forms; + +namespace SAM.Game +{ + internal static class Program + { + [STAThread] + public static void Main(string[] args) + { + long appId; + + if (args.Length == 0) + { + Process.Start("SAM.Picker.exe"); + return; + } + + if (long.TryParse(args[0], out appId) == false) + { + MessageBox.Show( + "Could not parse application ID from commandline argument.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + if (API.Steam.GetInstallPath() == Application.StartupPath) + { + MessageBox.Show( + "This tool declines to being run from the Steam directory.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + API.Client client; + try + { + client = new API.Client(); + + if (client.Initialize(appId) == false) + { + MessageBox.Show( + "Steam is not running. Please start Steam then run this tool again.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + } + catch (DllNotFoundException) + { + MessageBox.Show( + "You've caused an exceptional error!", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Manager(appId, client)); + } + } +} diff --git a/SAM.Game/Properties/AssemblyInfo.cs b/SAM.Game/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4d8f228 --- /dev/null +++ b/SAM.Game/Properties/AssemblyInfo.cs @@ -0,0 +1,61 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("Steam Achievement Manager")] +[assembly: AssemblyDescription("A manager for game achievements in Steam.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Gibbed")] +[assembly: AssemblyProduct("SAM.Game")] +[assembly: AssemblyCopyright("Copyright © Gibbed 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("0e6ba693-1ffa-44a0-a3eb-556272789273")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] + +[assembly: AssemblyVersion("7.0.0.0")] +[assembly: AssemblyFileVersion("7.0.0.0")] diff --git a/SAM.Game/Properties/Resources.Designer.cs b/SAM.Game/Properties/Resources.Designer.cs new file mode 100644 index 0000000..18c0c35 --- /dev/null +++ b/SAM.Game/Properties/Resources.Designer.cs @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SAM.Game.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SAM.Game.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap Download { + get { + object obj = ResourceManager.GetObject("Download", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Invert { + get { + object obj = ResourceManager.GetObject("Invert", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Lock { + get { + object obj = ResourceManager.GetObject("Lock", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Refresh { + get { + object obj = ResourceManager.GetObject("Refresh", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Reset { + get { + object obj = ResourceManager.GetObject("Reset", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Sad { + get { + object obj = ResourceManager.GetObject("Sad", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Save { + get { + object obj = ResourceManager.GetObject("Save", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Unlock { + get { + object obj = ResourceManager.GetObject("Unlock", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/SAM.Game/Properties/Resources.resx b/SAM.Game/Properties/Resources.resx new file mode 100644 index 0000000..97e7e78 --- /dev/null +++ b/SAM.Game/Properties/Resources.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\lock.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow-circle-double.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\lock-unlock.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\bomb.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\lock--pencil.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\transmitter.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\poop-smiley-sad-enlarged.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\download-cloud.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/SAM.Game/Resources/arrow-circle-double.png b/SAM.Game/Resources/arrow-circle-double.png new file mode 100644 index 0000000..ba5ebd1 Binary files /dev/null and b/SAM.Game/Resources/arrow-circle-double.png differ diff --git a/SAM.Game/Resources/bomb.png b/SAM.Game/Resources/bomb.png new file mode 100644 index 0000000..2e73168 Binary files /dev/null and b/SAM.Game/Resources/bomb.png differ diff --git a/SAM.Game/Resources/download-cloud.png b/SAM.Game/Resources/download-cloud.png new file mode 100644 index 0000000..ba0f492 Binary files /dev/null and b/SAM.Game/Resources/download-cloud.png differ diff --git a/SAM.Game/Resources/lock--pencil.png b/SAM.Game/Resources/lock--pencil.png new file mode 100644 index 0000000..9fc2cd6 Binary files /dev/null and b/SAM.Game/Resources/lock--pencil.png differ diff --git a/SAM.Game/Resources/lock-unlock.png b/SAM.Game/Resources/lock-unlock.png new file mode 100644 index 0000000..a9994ae Binary files /dev/null and b/SAM.Game/Resources/lock-unlock.png differ diff --git a/SAM.Game/Resources/lock.png b/SAM.Game/Resources/lock.png new file mode 100644 index 0000000..571c16d Binary files /dev/null and b/SAM.Game/Resources/lock.png differ diff --git a/SAM.Game/Resources/poop-smiley-sad-enlarged.png b/SAM.Game/Resources/poop-smiley-sad-enlarged.png new file mode 100644 index 0000000..33380b6 Binary files /dev/null and b/SAM.Game/Resources/poop-smiley-sad-enlarged.png differ diff --git a/SAM.Game/Resources/poop-smiley-sad.png b/SAM.Game/Resources/poop-smiley-sad.png new file mode 100644 index 0000000..a83afd7 Binary files /dev/null and b/SAM.Game/Resources/poop-smiley-sad.png differ diff --git a/SAM.Game/Resources/transmitter.png b/SAM.Game/Resources/transmitter.png new file mode 100644 index 0000000..cf4c656 Binary files /dev/null and b/SAM.Game/Resources/transmitter.png differ diff --git a/SAM.Game/SAM.Game.csproj b/SAM.Game/SAM.Game.csproj new file mode 100644 index 0000000..2f59e93 --- /dev/null +++ b/SAM.Game/SAM.Game.csproj @@ -0,0 +1,155 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7640DE31-E54E-45F9-9CF0-8DF3A3EA30FC} + WinExe + Properties + SAM.Game + SAM.Game + v3.5 + 512 + Blank.ico + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\bin\ + DEBUG;TRACE + prompt + 4 + x86 + AllRules.ruleset + + + none + true + ..\upload\ + TRACE + prompt + 4 + false + x86 + AllRules.ruleset + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + Component + + + + + Form + + + Manager.cs + + + + + Manager.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + + + + + + + + + + + + + + + + + + + + + + + + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1} + SAM.API + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + \ No newline at end of file diff --git a/SAM.Game/SAM.Game.csproj.DotSettings b/SAM.Game/SAM.Game.csproj.DotSettings new file mode 100644 index 0000000..6e7fff8 --- /dev/null +++ b/SAM.Game/SAM.Game.csproj.DotSettings @@ -0,0 +1,2 @@ + + No \ No newline at end of file diff --git a/SAM.Game/Stats/AchievementDefinition.cs b/SAM.Game/Stats/AchievementDefinition.cs new file mode 100644 index 0000000..968860c --- /dev/null +++ b/SAM.Game/Stats/AchievementDefinition.cs @@ -0,0 +1,35 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal class AchievementDefinition + { + public string Id; + public string Name; + public string Description; + public string IconNormal; + public string IconLocked; + public bool IsHidden; + public int Permission; + } +} diff --git a/SAM.Game/Stats/AchievementInfo.cs b/SAM.Game/Stats/AchievementInfo.cs new file mode 100644 index 0000000..b598053 --- /dev/null +++ b/SAM.Game/Stats/AchievementInfo.cs @@ -0,0 +1,47 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Windows.Forms; + +namespace SAM.Game.Stats +{ + internal class AchievementInfo + { + public string Id; + public bool IsAchieved; + public int Permission; + public string IconNormal; + public string IconLocked; + public string Name; + public string Description; + public ListViewItem Item; + + #region public int ImageIndex; + public int ImageIndex + { + get { return this.Item.ImageIndex; } + + set { this.Item.ImageIndex = value; } + } + #endregion + } +} diff --git a/SAM.Game/Stats/FloatStatDefinition.cs b/SAM.Game/Stats/FloatStatDefinition.cs new file mode 100644 index 0000000..fd0c400 --- /dev/null +++ b/SAM.Game/Stats/FloatStatDefinition.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal class FloatStatDefinition : StatDefinition + { + public float MinValue; + public float MaxValue; + public float MaxChange; + public bool IncrementOnly; + public float DefaultValue; + } +} diff --git a/SAM.Game/Stats/FloatStatInfo.cs b/SAM.Game/Stats/FloatStatInfo.cs new file mode 100644 index 0000000..7a12884 --- /dev/null +++ b/SAM.Game/Stats/FloatStatInfo.cs @@ -0,0 +1,52 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal class FloatStatInfo : StatInfo + { + public float OriginalValue; + public float FloatValue; + + public override object Value + { + get { return this.FloatValue; } + set + { + var f = float.Parse((string)value); + + if ((this.Permission & 2) != 0 && + this.FloatValue.Equals(f) == false) + { + throw new StatIsProtectedException(); + } + + this.FloatValue = f; + } + } + + public override bool IsModified + { + get { return this.FloatValue.Equals(this.OriginalValue) == false; } + } + } +} diff --git a/SAM.Game/Stats/IntStatInfo.cs b/SAM.Game/Stats/IntStatInfo.cs new file mode 100644 index 0000000..9e7a644 --- /dev/null +++ b/SAM.Game/Stats/IntStatInfo.cs @@ -0,0 +1,52 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal class IntStatInfo : StatInfo + { + public int OriginalValue; + public int IntValue; + + public override object Value + { + get { return this.IntValue; } + set + { + var i = int.Parse((string)value); + + if ((this.Permission & 2) != 0 && + this.IntValue != i) + { + throw new StatIsProtectedException(); + } + + this.IntValue = i; + } + } + + public override bool IsModified + { + get { return this.IntValue != this.OriginalValue; } + } + } +} diff --git a/SAM.Game/Stats/IntegerStatDefinition.cs b/SAM.Game/Stats/IntegerStatDefinition.cs new file mode 100644 index 0000000..899c761 --- /dev/null +++ b/SAM.Game/Stats/IntegerStatDefinition.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal class IntegerStatDefinition : StatDefinition + { + public int MinValue; + public int MaxValue; + public int MaxChange; + public bool IncrementOnly; + public int DefaultValue; + } +} diff --git a/SAM.Game/Stats/StatDefinition.cs b/SAM.Game/Stats/StatDefinition.cs new file mode 100644 index 0000000..f44db10 --- /dev/null +++ b/SAM.Game/Stats/StatDefinition.cs @@ -0,0 +1,31 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal abstract class StatDefinition + { + public string Id; + public string DisplayName; + public int Permission; + } +} diff --git a/SAM.Game/Stats/StatFlags.cs b/SAM.Game/Stats/StatFlags.cs new file mode 100644 index 0000000..fe3b771 --- /dev/null +++ b/SAM.Game/Stats/StatFlags.cs @@ -0,0 +1,35 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; + +namespace SAM.Game.Stats +{ + [Flags] + internal enum StatFlags + { + None = 0, + IncrementOnly = 1 << 0, + Protected = 1 << 1, + UnknownPermission = 1 << 2, + } +} diff --git a/SAM.Game/Stats/StatInfo.cs b/SAM.Game/Stats/StatInfo.cs new file mode 100644 index 0000000..92d1b12 --- /dev/null +++ b/SAM.Game/Stats/StatInfo.cs @@ -0,0 +1,46 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +namespace SAM.Game.Stats +{ + internal abstract class StatInfo + { + public abstract bool IsModified { get; } + public string Id { get; set; } + public string DisplayName { get; set; } + public abstract object Value { get; set; } + public bool IsIncrementOnly { get; set; } + public int Permission { get; set; } + + public string Extra + { + get + { + var flags = StatFlags.None; + flags |= this.IsIncrementOnly == false ? 0 : StatFlags.IncrementOnly; + flags |= ((this.Permission & 2) != 0) == false ? 0 : StatFlags.Protected; + flags |= ((this.Permission & ~2) != 0) == false ? 0 : StatFlags.UnknownPermission; + return flags.ToString(); + } + } + } +} diff --git a/SAM.Game/Stats/StatIsProtectedException.cs b/SAM.Game/Stats/StatIsProtectedException.cs new file mode 100644 index 0000000..293a3de --- /dev/null +++ b/SAM.Game/Stats/StatIsProtectedException.cs @@ -0,0 +1,30 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; + +namespace SAM.Game.Stats +{ + internal class StatIsProtectedException : Exception + { + } +} diff --git a/SAM.Game/StreamHelpers.cs b/SAM.Game/StreamHelpers.cs new file mode 100644 index 0000000..ca51cda --- /dev/null +++ b/SAM.Game/StreamHelpers.cs @@ -0,0 +1,115 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +namespace SAM.Game +{ + internal static class StreamHelpers + { + public static byte ReadValueU8(this Stream stream) + { + return (byte)stream.ReadByte(); + } + + public static int ReadValueS32(this Stream stream) + { + var data = new byte[4]; + int read = stream.Read(data, 0, 4); + Debug.Assert(read == 4); + return BitConverter.ToInt32(data, 0); + } + + public static uint ReadValueU32(this Stream stream) + { + var data = new byte[4]; + int read = stream.Read(data, 0, 4); + Debug.Assert(read == 4); + return BitConverter.ToUInt32(data, 0); + } + + public static ulong ReadValueU64(this Stream stream) + { + var data = new byte[8]; + int read = stream.Read(data, 0, 8); + Debug.Assert(read == 8); + return BitConverter.ToUInt64(data, 0); + } + + public static float ReadValueF32(this Stream stream) + { + var data = new byte[4]; + int read = stream.Read(data, 0, 4); + Debug.Assert(read == 4); + return BitConverter.ToSingle(data, 0); + } + + internal static string ReadStringInternalDynamic(this Stream stream, Encoding encoding, char end) + { + int characterSize = encoding.GetByteCount("e"); + Debug.Assert(characterSize == 1 || characterSize == 2 || characterSize == 4); + string characterEnd = end.ToString(CultureInfo.InvariantCulture); + + int i = 0; + var data = new byte[128 * characterSize]; + + while (true) + { + if (i + characterSize > data.Length) + { + Array.Resize(ref data, data.Length + (128 * characterSize)); + } + + int read = stream.Read(data, i, characterSize); + Debug.Assert(read == characterSize); + + if (encoding.GetString(data, i, characterSize) == characterEnd) + { + break; + } + + i += characterSize; + } + + if (i == 0) + { + return ""; + } + + return encoding.GetString(data, 0, i); + } + + public static string ReadStringAscii(this Stream stream) + { + return stream.ReadStringInternalDynamic(Encoding.ASCII, '\0'); + } + + public static string ReadStringUnicode(this Stream stream) + { + return stream.ReadStringInternalDynamic(Encoding.UTF8, '\0'); + } + } +} diff --git a/SAM.Picker/DoubleBufferedListView.cs b/SAM.Picker/DoubleBufferedListView.cs new file mode 100644 index 0000000..fc31aed --- /dev/null +++ b/SAM.Picker/DoubleBufferedListView.cs @@ -0,0 +1,34 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Windows.Forms; + +namespace SAM.Picker +{ + internal class DoubleBufferedListView : ListView + { + public DoubleBufferedListView() + { + base.DoubleBuffered = true; + } + } +} diff --git a/SAM.Picker/GameInfo.cs b/SAM.Picker/GameInfo.cs new file mode 100644 index 0000000..4b8101a --- /dev/null +++ b/SAM.Picker/GameInfo.cs @@ -0,0 +1,68 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Globalization; +using System.Windows.Forms; + +namespace SAM.Picker +{ + internal class GameInfo + { + public long Id; + public string Type; + public ListViewItem Item; + + #region public string Name; + public string Name + { + get { return this.Item.Text; } + + set { this.Item.Text = value ?? "App " + this.Id.ToString(CultureInfo.InvariantCulture); } + } + #endregion + + #region public int ImageIndex; + public int ImageIndex + { + get { return this.Item.ImageIndex; } + + set { this.Item.ImageIndex = value; } + } + #endregion + + public string Logo; + + public GameInfo(Int64 id, string type) + { + this.Id = id; + this.Type = type; + this.Item = new ListViewItem() + { + Tag = this, + }; + this.Name = null; + this.ImageIndex = 0; + this.Logo = null; + } + } +} diff --git a/SAM.Picker/GamePicker.Designer.cs b/SAM.Picker/GamePicker.Designer.cs new file mode 100644 index 0000000..92265c4 --- /dev/null +++ b/SAM.Picker/GamePicker.Designer.cs @@ -0,0 +1,245 @@ +namespace SAM.Picker +{ + partial class GamePicker + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.ToolStripSeparator _ToolStripSeparator1; + System.Windows.Forms.ToolStripSeparator _ToolStripSeparator2; + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GamePicker)); + this._GameLogoImageList = new System.Windows.Forms.ImageList(this.components); + this._CallbackTimer = new System.Windows.Forms.Timer(this.components); + this._PickerToolStrip = new System.Windows.Forms.ToolStrip(); + this._RefreshGamesButton = new System.Windows.Forms.ToolStripButton(); + this._AddGameTextBox = new System.Windows.Forms.ToolStripTextBox(); + this._AddGameButton = new System.Windows.Forms.ToolStripButton(); + this._FilterDropDownButton = new System.Windows.Forms.ToolStripDropDownButton(); + this._FilterGamesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._FilterDemosMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._FilterModsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._FilterJunkMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this._GameListView = new SAM.Picker.DoubleBufferedListView(); + this._PickerStatusStrip = new System.Windows.Forms.StatusStrip(); + this._PickerStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + this._DownloadStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); + _ToolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + _ToolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this._PickerToolStrip.SuspendLayout(); + this._PickerStatusStrip.SuspendLayout(); + this.SuspendLayout(); + // + // _GameLogoImageList + // + this._GameLogoImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit; + this._GameLogoImageList.ImageSize = new System.Drawing.Size(184, 69); + this._GameLogoImageList.TransparentColor = System.Drawing.Color.Transparent; + // + // _CallbackTimer + // + this._CallbackTimer.Enabled = true; + this._CallbackTimer.Tick += new System.EventHandler(this.OnTimer); + // + // _PickerToolStrip + // + this._PickerToolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this._RefreshGamesButton, + _ToolStripSeparator1, + this._AddGameTextBox, + this._AddGameButton, + _ToolStripSeparator2, + this._FilterDropDownButton}); + this._PickerToolStrip.Location = new System.Drawing.Point(0, 0); + this._PickerToolStrip.Name = "_PickerToolStrip"; + this._PickerToolStrip.Size = new System.Drawing.Size(742, 25); + this._PickerToolStrip.TabIndex = 1; + this._PickerToolStrip.Text = "toolStrip1"; + // + // _RefreshGamesButton + // + this._RefreshGamesButton.Image = global::SAM.Picker.Properties.Resources.Refresh; + this._RefreshGamesButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._RefreshGamesButton.Name = "_RefreshGamesButton"; + this._RefreshGamesButton.Size = new System.Drawing.Size(105, 22); + this._RefreshGamesButton.Text = "Refresh Games"; + this._RefreshGamesButton.Click += new System.EventHandler(this.OnRefresh); + // + // _ToolStripSeparator1 + // + _ToolStripSeparator1.Name = "_ToolStripSeparator1"; + _ToolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // + // _AddGameTextBox + // + this._AddGameTextBox.Name = "_AddGameTextBox"; + this._AddGameTextBox.Size = new System.Drawing.Size(100, 25); + // + // _AddGameButton + // + this._AddGameButton.Image = global::SAM.Picker.Properties.Resources.Search; + this._AddGameButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._AddGameButton.Name = "_AddGameButton"; + this._AddGameButton.Size = new System.Drawing.Size(83, 22); + this._AddGameButton.Text = "Add Game"; + this._AddGameButton.Click += new System.EventHandler(this.OnAddGame); + // + // _ToolStripSeparator2 + // + _ToolStripSeparator2.Name = "_ToolStripSeparator2"; + _ToolStripSeparator2.Size = new System.Drawing.Size(6, 25); + // + // _FilterDropDownButton + // + this._FilterDropDownButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this._FilterDropDownButton.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this._FilterGamesMenuItem, + this._FilterDemosMenuItem, + this._FilterModsMenuItem, + this._FilterJunkMenuItem}); + this._FilterDropDownButton.Image = global::SAM.Picker.Properties.Resources.Filter; + this._FilterDropDownButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this._FilterDropDownButton.Name = "_FilterDropDownButton"; + this._FilterDropDownButton.Size = new System.Drawing.Size(29, 22); + this._FilterDropDownButton.Text = "Game filtering"; + // + // _FilterGamesMenuItem + // + this._FilterGamesMenuItem.Checked = true; + this._FilterGamesMenuItem.CheckOnClick = true; + this._FilterGamesMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + this._FilterGamesMenuItem.Name = "_FilterGamesMenuItem"; + this._FilterGamesMenuItem.Size = new System.Drawing.Size(152, 22); + this._FilterGamesMenuItem.Text = "Show &games"; + this._FilterGamesMenuItem.CheckedChanged += new System.EventHandler(this.OnFilterUpdate); + // + // _FilterDemosMenuItem + // + this._FilterDemosMenuItem.CheckOnClick = true; + this._FilterDemosMenuItem.Name = "_FilterDemosMenuItem"; + this._FilterDemosMenuItem.Size = new System.Drawing.Size(152, 22); + this._FilterDemosMenuItem.Text = "Show &demos"; + this._FilterDemosMenuItem.CheckedChanged += new System.EventHandler(this.OnFilterUpdate); + // + // _FilterModsMenuItem + // + this._FilterModsMenuItem.CheckOnClick = true; + this._FilterModsMenuItem.Name = "_FilterModsMenuItem"; + this._FilterModsMenuItem.Size = new System.Drawing.Size(152, 22); + this._FilterModsMenuItem.Text = "Show &mods"; + this._FilterModsMenuItem.CheckedChanged += new System.EventHandler(this.OnFilterUpdate); + // + // _FilterJunkMenuItem + // + this._FilterJunkMenuItem.CheckOnClick = true; + this._FilterJunkMenuItem.Name = "_FilterJunkMenuItem"; + this._FilterJunkMenuItem.Size = new System.Drawing.Size(152, 22); + this._FilterJunkMenuItem.Text = "Show &junk"; + this._FilterJunkMenuItem.CheckedChanged += new System.EventHandler(this.OnFilterUpdate); + // + // _GameListView + // + this._GameListView.BackColor = System.Drawing.Color.Black; + this._GameListView.Dock = System.Windows.Forms.DockStyle.Fill; + this._GameListView.ForeColor = System.Drawing.Color.White; + this._GameListView.LargeImageList = this._GameLogoImageList; + this._GameListView.Location = new System.Drawing.Point(0, 25); + this._GameListView.MultiSelect = false; + this._GameListView.Name = "_GameListView"; + this._GameListView.Size = new System.Drawing.Size(742, 245); + this._GameListView.SmallImageList = this._GameLogoImageList; + this._GameListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + this._GameListView.TabIndex = 0; + this._GameListView.TileSize = new System.Drawing.Size(184, 69); + this._GameListView.UseCompatibleStateImageBehavior = false; + this._GameListView.ItemActivate += new System.EventHandler(this.OnSelectGame); + // + // _PickerStatusStrip + // + this._PickerStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this._PickerStatusLabel, + this._DownloadStatusLabel}); + this._PickerStatusStrip.Location = new System.Drawing.Point(0, 270); + this._PickerStatusStrip.Name = "_PickerStatusStrip"; + this._PickerStatusStrip.Size = new System.Drawing.Size(742, 22); + this._PickerStatusStrip.TabIndex = 2; + this._PickerStatusStrip.Text = "statusStrip"; + // + // _PickerStatusLabel + // + this._PickerStatusLabel.Name = "_PickerStatusLabel"; + this._PickerStatusLabel.Size = new System.Drawing.Size(727, 17); + this._PickerStatusLabel.Spring = true; + this._PickerStatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // _DownloadStatusLabel + // + this._DownloadStatusLabel.Image = global::SAM.Picker.Properties.Resources.Download; + this._DownloadStatusLabel.Name = "_DownloadStatusLabel"; + this._DownloadStatusLabel.Size = new System.Drawing.Size(111, 17); + this._DownloadStatusLabel.Text = "Download status"; + this._DownloadStatusLabel.Visible = false; + // + // GamePicker + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(742, 292); + this.Controls.Add(this._GameListView); + this.Controls.Add(this._PickerStatusStrip); + this.Controls.Add(this._PickerToolStrip); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "GamePicker"; + this.Text = "Steam Achievement Manager 6.3 | Pick a game... Any game..."; + this._PickerToolStrip.ResumeLayout(false); + this._PickerToolStrip.PerformLayout(); + this._PickerStatusStrip.ResumeLayout(false); + this._PickerStatusStrip.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private DoubleBufferedListView _GameListView; + private System.Windows.Forms.ImageList _GameLogoImageList; + private System.Windows.Forms.Timer _CallbackTimer; + private System.Windows.Forms.ToolStrip _PickerToolStrip; + private System.Windows.Forms.ToolStripButton _RefreshGamesButton; + private System.Windows.Forms.ToolStripTextBox _AddGameTextBox; + private System.Windows.Forms.ToolStripButton _AddGameButton; + private System.Windows.Forms.ToolStripDropDownButton _FilterDropDownButton; + private System.Windows.Forms.ToolStripMenuItem _FilterGamesMenuItem; + private System.Windows.Forms.ToolStripMenuItem _FilterJunkMenuItem; + private System.Windows.Forms.ToolStripMenuItem _FilterDemosMenuItem; + private System.Windows.Forms.ToolStripMenuItem _FilterModsMenuItem; + private System.Windows.Forms.StatusStrip _PickerStatusStrip; + private System.Windows.Forms.ToolStripStatusLabel _DownloadStatusLabel; + private System.Windows.Forms.ToolStripStatusLabel _PickerStatusLabel; + } +} + diff --git a/SAM.Picker/GamePicker.cs b/SAM.Picker/GamePicker.cs new file mode 100644 index 0000000..528e04d --- /dev/null +++ b/SAM.Picker/GamePicker.cs @@ -0,0 +1,368 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Windows.Forms; +using System.Xml.XPath; +using APITypes = SAM.API.Types; + +namespace SAM.Picker +{ + internal partial class GamePicker : Form + { + private readonly API.Client _SteamClient; + + private readonly WebClient _GameListDownloader = new WebClient(); + private readonly WebClient _LogoDownloader = new WebClient(); + private List _Games = new List(); + + public List Games + { + get { return _Games; } + } + + private readonly List _LogoQueue = new List(); + + // ReSharper disable PrivateFieldCanBeConvertedToLocalVariable + private readonly API.Callbacks.AppDataChanged _AppDataChangedCallback; + // ReSharper restore PrivateFieldCanBeConvertedToLocalVariable + + public GamePicker(API.Client client) + { + this.InitializeComponent(); + + this._GameLogoImageList.Images.Add( + "Blank", + new Bitmap(this._GameLogoImageList.ImageSize.Width, this._GameLogoImageList.ImageSize.Height)); + + this._GameListDownloader.DownloadDataCompleted += this.OnGameListDownload; + this._LogoDownloader.DownloadDataCompleted += this.OnLogoDownload; + + this._SteamClient = client; + + this._AppDataChangedCallback = client.CreateAndRegisterCallback(); + this._AppDataChangedCallback.OnRun += this.OnAppDataChanged; + + this.AddGames(); + } + + private void OnAppDataChanged(APITypes.AppDataChanged param) + { + if (param.Result == true) + { + foreach (GameInfo info in this._Games) + { + if (info.Id == param.Id) + { + info.Name = this._SteamClient.SteamApps001.GetAppData((uint)info.Id, "name"); + this.AddGameToLogoQueue(info); + this._GameListView.Sort(); + this._GameListView.Update(); + break; + } + } + } + } + + private void OnGameListDownload(object sender, DownloadDataCompletedEventArgs e) + { + if (e.Error == null && e.Cancelled == false) + { + using (var stream = new MemoryStream()) + { + stream.Write(e.Result, 0, e.Result.Length); + stream.Seek(0, SeekOrigin.Begin); + + var document = new XPathDocument(stream); + var navigator = document.CreateNavigator(); + var nodes = navigator.Select("/games/game"); + while (nodes.MoveNext()) + { + string type = nodes.Current.GetAttribute("type", ""); + + if (type == string.Empty) + { + type = "normal"; + } + + this.AddGame(nodes.Current.ValueAsLong, type); + } + } + } + else + { + this.AddDefaultGames(); + //MessageBox.Show(e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + this.RefreshGames(); + this._RefreshGamesButton.Enabled = true; + this.DownloadNextLogo(); + } + + private void RefreshGames() + { + this._GameListView.BeginUpdate(); + this._GameListView.Items.Clear(); + + foreach (GameInfo info in this._Games) + { + if (info.Type == "normal" && + _FilterGamesMenuItem.Checked == false) + { + continue; + } + + if (info.Type == "demo" && + this._FilterDemosMenuItem.Checked == false) + { + continue; + } + + if (info.Type == "mod" && + this._FilterModsMenuItem.Checked == false) + { + continue; + } + + if (info.Type == "junk" && + this._FilterJunkMenuItem.Checked == false) + { + continue; + } + + this._GameListView.Items.Add(info.Item); + } + + this._GameListView.EndUpdate(); + this._PickerStatusLabel.Text = string.Format( + "Displaying {0} games. Total {1} games.", + this._GameListView.Items.Count, + this._Games.Count); + } + + private void OnLogoDownload(object sender, DownloadDataCompletedEventArgs e) + { + if (e.Error == null && e.Cancelled == false) + { + var info = e.UserState as GameInfo; + if (info != null) + { + Image logo; + try + { + using (var stream = new MemoryStream()) + { + stream.Write(e.Result, 0, e.Result.Length); + logo = new Bitmap(stream); + } + } + catch + { + logo = null; + } + + if (logo != null) + { + info.ImageIndex = this._GameLogoImageList.Images.Count; + this._GameLogoImageList.Images.Add(info.Logo, logo); + this._GameListView.Update(); + } + } + } + + this.DownloadNextLogo(); + } + + private void DownloadNextLogo() + { + if (this._LogoQueue.Count == 0) + { + this._DownloadStatusLabel.Visible = false; + return; + } + + if (this._LogoDownloader.IsBusy) + { + return; + } + + this._DownloadStatusLabel.Text = string.Format( + "Downloading {0} game icons...", + this._LogoQueue.Count); + this._DownloadStatusLabel.Visible = true; + + GameInfo info = this._LogoQueue[0]; + this._LogoQueue.RemoveAt(0); + + var logoPath = string.Format( + "http://media.steamcommunity.com/steamcommunity/public/images/apps/{0}/{1}.jpg", + info.Id, + info.Logo); + this._LogoDownloader.DownloadDataAsync(new Uri(logoPath), info); + } + + private void AddGameToLogoQueue(GameInfo info) + { + string logo = this._SteamClient.SteamApps001.GetAppData((uint)info.Id, "logo"); + + if (logo == null) + { + return; + } + + info.Logo = logo; + + int imageIndex = this._GameLogoImageList.Images.IndexOfKey(logo); + if (imageIndex >= 0) + { + info.ImageIndex = imageIndex; + } + else + { + this._LogoQueue.Add(info); + this.DownloadNextLogo(); + } + } + + private bool OwnsGame(long id) + { + return this._SteamClient.SteamApps003.IsSubscribedApp(id); + } + + private void AddGame(long id, string type) + { + if (this._Games.Any(i => i.Id == id) == true) + { + return; + } + + if (this.OwnsGame(id) == false) + { + return; + } + + var info = new GameInfo(id, type); + info.Name = this._SteamClient.SteamApps001.GetAppData((uint)info.Id, "name"); + + this._Games.Add(info); + this.AddGameToLogoQueue(info); + } + + private void AddGames() + { + this._GameListView.Items.Clear(); + this._Games = new List(); + this._GameListDownloader.DownloadDataAsync(new Uri(string.Format("http://gib.me/sam/games.xml"))); + this._RefreshGamesButton.Enabled = false; + } + + private void AddDefaultGames() + { + this.AddGame(480, "normal"); // Spacewar + } + + private void OnTimer(object sender, EventArgs e) + { + this._CallbackTimer.Enabled = false; + this._SteamClient.RunCallbacks(false); + this._CallbackTimer.Enabled = true; + } + + private void OnSelectGame(object sender, EventArgs e) + { + if (this._GameListView.SelectedItems.Count == 0) + { + return; + } + + var info = this._GameListView.SelectedItems[0].Tag as GameInfo; + if (info == null) + { + return; + } + + try + { + Process.Start("SAM.Game.exe", info.Id.ToString(CultureInfo.InvariantCulture)); + } + catch (Win32Exception) + { + MessageBox.Show( + this, + "Failed to start SAM.Game.exe.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + private void OnRefresh(object sender, EventArgs e) + { + this._AddGameTextBox.Text = ""; + this.AddGames(); + } + + private void OnAddGame(object sender, EventArgs e) + { + long id; + + if (long.TryParse(this._AddGameTextBox.Text, out id) == false) + { + MessageBox.Show( + this, + "Please enter a valid game ID.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + if (this.OwnsGame(id) == false) + { + MessageBox.Show(this, "You don't own that game.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + this._AddGameTextBox.Text = ""; + this._GameListView.Items.Clear(); + this._Games = new List(); + this.AddGame(id, "normal"); + this._FilterGamesMenuItem.Checked = true; + this.RefreshGames(); + this.DownloadNextLogo(); + } + + private void OnFilterUpdate(object sender, EventArgs e) + { + this.RefreshGames(); + } + } +} diff --git a/SAM.Picker/GamePicker.resx b/SAM.Picker/GamePicker.resx new file mode 100644 index 0000000..0b81a1f --- /dev/null +++ b/SAM.Picker/GamePicker.resx @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 233, 17 + + + 359, 17 + + + False + + + False + + + 464, 17 + + + + + AAABAAMAEBAAAAEACABoBQAANgAAACAgAAABAAgAqAgAAJ4FAAAwMAAAAQAYAKgcAABGDgAAKAAAABAA + AAAgAAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAgP8A////AMXKxwD///8ADQkMAJus + oQBeW10AwNXIAIyMjAC2trYAa29tAHVzdAC5v7wAj5aRAHx8fACRjI8AstnBAGGCbgAlNisAPFFGAHCX + gACbq6EAgX+AAHp4egDA1cgAR2FSADApLgChsKcAj5aRAGtvbQBih3EAX15fAIODgwCTj5IApcKyABwb + GwC0vbcAYIJtAGmJdgBjZ2UAoLKmADJEOQCGhIUAd3Z2ALa2tgB2nYYAXltdAIafjwBnhXQAcY9+ADFE + OACzyrwALD0zAHZ0dQCFgYMArsW4AGeHcwBHSEgAhpqNAG6PfABtjnoAJiUlALDGuQAWIBsAhIODAHh3 + eADFyscAbY96AGmGdQBshncAio+MAEVFRABDP0IAqbauAGOEcAAdGhwAioqKALm/vACLh4kAdXJ0AIWC + hAC5xr8Ah6yWAGSAcABrh3cAaod2AGyMeQCbr6MAjaqZAEVdTwAJBgcAi4uLAF5/awCfuKkArcO1AJus + oQBGYFEAX3tqAGuIeABphnQACw8NAC4sLgBMSksAjo6OAGWDcgBif20AYX9tAJWyoQBrdW8Abo56AHiY + hgBMYlUADQkMAIOCgwCMjIwAhYWFAGyLeQBqh3cAaYd1AEZTSwCmxbQAGCMcAC8qLACQkJAAgYGBAFhb + WQBvjHsAX3hpAHGRfwB9oIoAHCYfAKS/sAAvKi4AkpKSAK6wrwBlgXAAUVZTACIkIgCChIMAL0U3AHRy + cwB9fH0AdXR1AGmCcwBwinsAMUc5AEVARACEg4QAdnN1AGJgYQB8enwAh4eHAAAAAAD///8AAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEAAQEBAQIC + AQEBAQEBAQEBAQEBAQIBAQIBAQEBAQEBAQEBAQIBAgIBAgEBAQEBAQEBAgICAgICAQIBAQEBAQEBAQIC + AgICAgECAgEBAQEBAQECAgICAgECAgICAQEBAQEBAgIBAQICAgICAgICAgEBAQEBAQEBAQICAgICAgIC + AQEBAQEBAQECAgICAQEBAQIBAQEBAQEBAQICAQICAgECAQEBAQEBAQEBAgECAgIBAgEBAQEBAQEBAQIB + AgICAQIBAQEBAQEBAQECAgEBAQICAQEBAQEBAQEBAQICAgICAQEAAQEBAQEBAQEBAQEBAQEAgAEAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAACgA + AAAgAAAAQAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwID/AP///wCAgAAAAIAAAACA + gAAAAIAAwMDAAMDcwADwyqYAgICAAP8A/wD/AAAA//8AAAD/AAAA//8AAAD/AP///wDw+/8ApKCgANTw + /wCx4v8AjtT/AGvG/wBIuP8AJar/AACq/wAAktwAAHq5AABilgAASnMAADJQANTj/wCxx/8Ajqv/AGuP + /wBIc/8AJVf/AABV/wAASdwAAD25AAAxlgAAJXMAABlQANTU/wCxsf8Ajo7/AGtr/wBISP8AJSX/AAAA + /wAAANwAAAC5AAAAlgAAAHMAAABQAOPU/wDHsf8Aq47/AI9r/wBzSP8AVyX/AFUA/wBJANwAPQC5ADEA + lgAlAHMAGQBQAPDU/wDisf8A1I7/AMZr/wC4SP8AqiX/AKoA/wCSANwAegC5AGIAlgBKAHMAMgBQAP/U + /wD/sf8A/47/AP9r/wD/SP8A/yX/AP8A/wDcANwAuQC5AJYAlgBzAHMAUABQAP/U8AD/seIA/47UAP9r + xgD/SLgA/yWqAP8AqgDcAJIAuQB6AJYAYgBzAEoAUAAyAP/U4wD/sccA/46rAP9rjwD/SHMA/yVXAP8A + VQDcAEkAuQA9AJYAMQBzACUAUAAZAP/U1AD/sbEA/46OAP9rawD/SEgA/yUlAP8AAADcAAAAuQAAAJYA + AABzAAAAUAAAAP/j1AD/x7EA/6uOAP+PawD/c0gA/1clAP9VAADcSQAAuT0AAJYxAABzJQAAUBkAAP/w + 1AD/4rEA/9SOAP/GawD/uEgA/6olAP+qAADckgAAuXoAAJZiAABzSgAAUDIAAP//1AD//7EA//+OAP// + awD//0gA//8lAP//AADc3AAAubkAAJaWAABzcwAAUFAAAPD/1ADi/7EA1P+OAMb/awC4/0gAqv8lAKr/ + AACS3AAAerkAAGKWAABKcwAAMlAAAOP/1ADH/7EAq/+OAI//awBz/0gAV/8lAFX/AABJ3AAAPbkAADGW + AAAlcwAAGVAAANT/1ACx/7EAjv+OAGv/awBI/0gAJf8lAAD/AAAA3AAAALkAAACWAAAAcwAAAFAAANT/ + 4wCx/8cAjv+rAGv/jwBI/3MAJf9XAAD/VQAA3EkAALk9AACWMQAAcyUAAFAZANT/8ACx/+IAjv/UAGv/ + xgBI/7gAJf+qAAD/qgAA3JIAALl6AACWYgAAc0oAAFAyANT//wCx//8Ajv//AGv//wBI//8AJf//AAD/ + /wAA3NwAALm5AACWlgAAc3MAAFBQAPLy8gDm5uYA2traAM7OzgDCwsIAtra2AKqqqgCenp4AkpKSAIaG + hgB6enoAbm5uAGJiYgBWVlYASkpKAD4+PgAyMjIAJiYmABoaGgAODg4AAAABAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQIBAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQECAQICAgECAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgIB + AgIBAQEBAQEBAQEBAQEBAQEBAQEBAQICAgICAgICAQICAgIBAQEBAQEBAQEBAQEBAQEBAQICAgICAgIB + AQICAgICAgICAgEBAQEBAQECAgIBAgICAgICAgIBAQEBAQECAgICAgICAgEBAQEBAgIBAQICAgICAgIC + AQEBAQEBAQICAgIBAQEBAgEBAQECAQICAgICAgIBAQEBAQEBAQEBAQICAQICAgECAQEBAQIBAgICAgIB + AQEBAQEBAQEBAQEBAQIBAgICAQIBAQEBAgIBAQICAQEBAQEBAQEBAQEBAQEBAgECAgIBAgEBAQEBAgIC + AgEBAQEBAQEBAQEBAQEBAQECAgEBAQICAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQECAgICAgEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEB + AQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAMAAAAOAAAABAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAHAAAADKAAAADAA + AABgAAAAAQAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/wAAAAAAAAAA + AMCA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/wAAAMCA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/////////////////////8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/////8CA + /8CA/8CA/8CA/8CA/////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/////////////////////////8CA/8CA/////8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//////////////////////////////// + /8CA/////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//////////// + /////////////////////////////////8CA/////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/////////////////////////////////////////////////8CA/8CA//////////// + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//////////////////////////////////////////////// + /////8CA/8CA/8CA/////////////////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//////////////////////// + /////////////////////////////////////////////////////////////////////////////8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//// + /////////////////////////////////////////////////////8CA/8CA/8CA/8CA/8CA//////// + /////////////////////////////////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /////////////8CA/8CA/////////////////////////////////////////////////////8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA//////////////////////////////////////////////////// + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/////8CA/8CA//////////////////////////////////////// + /////////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//////////////////// + /////8CA/8CA/8CA/8CA/8CA/////////8CA/8CA/8CA/8CA/8CA/8CA/////8CA/8CA//////////// + /////////////////////////////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/////////////////8CA/8CA/////////////8CA/8CA/////////8CA/8CA/8CA + /8CA/////8CA/8CA/////////////////////////////////////////////8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/////////////8CA//////////// + /////////8CA/////////8CA/8CA/8CA/8CA/////8CA/8CA//////////////////////////////// + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/////////8CA/8CA/////////////////////8CA/8CA/////8CA/8CA/8CA/8CA/////8CA/8CA + /////////////////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/////////8CA/8CA/////////////////////8CA//// + /////8CA/8CA/8CA/8CA/8CA/////8CA/8CA/////////8CA/////////8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA//////// + /8CA/////////////////8CA/8CA/////////8CA/8CA/8CA/8CA/8CA/8CA/////8CA/8CA/8CA//// + /////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/////////////8CA/8CA/8CA/8CA/8CA/////////////8CA/8CA/8CA + /8CA/8CA/8CA/8CA/////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/////////////8CA/8CA + /8CA/////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/////////////////////////////8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/////8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/wAA + AMCA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/wAAAAAAAAAAAMCA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA + /8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/8CA/wAAAAAAAMAAAAAAAwAAgAAAAAAB + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAB + AADAAAAAAAMAAA== + + + \ No newline at end of file diff --git a/SAM.Picker/LICENSE.txt b/SAM.Picker/LICENSE.txt new file mode 100644 index 0000000..43d0120 --- /dev/null +++ b/SAM.Picker/LICENSE.txt @@ -0,0 +1,22 @@ +zlib License + +Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. \ No newline at end of file diff --git a/SAM.Picker/Program.cs b/SAM.Picker/Program.cs new file mode 100644 index 0000000..f04f688 --- /dev/null +++ b/SAM.Picker/Program.cs @@ -0,0 +1,72 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System; +using System.Windows.Forms; + +namespace SAM.Picker +{ + internal static class Program + { + [STAThread] + private static void Main() + { + if (API.Steam.GetInstallPath() == Application.StartupPath) + { + MessageBox.Show( + "This tool declines to being run from the Steam directory.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + API.Client client; + try + { + client = new API.Client(); + if (client.Initialize(0) == false) + { + MessageBox.Show( + "Steam is not running. Please start Steam then run this tool again.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + } + catch (DllNotFoundException) + { + MessageBox.Show( + "You've caused an exceptional error!", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new GamePicker(client)); + } + } +} diff --git a/SAM.Picker/Properties/AssemblyInfo.cs b/SAM.Picker/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..786b3a3 --- /dev/null +++ b/SAM.Picker/Properties/AssemblyInfo.cs @@ -0,0 +1,61 @@ +/* Copyright (c) 2017 Rick (rick 'at' gibbed 'dot' us) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("Steam Achievement Manager Picker")] +[assembly: AssemblyDescription("A game picker for the Steam Achievement Manager.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Gibbed")] +[assembly: AssemblyProduct("SAM.Picker")] +[assembly: AssemblyCopyright("Copyright © Gibbed 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("e133af48-a6c2-4890-8237-9552e0d325ac")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] + +[assembly: AssemblyVersion("7.0.0.0")] +[assembly: AssemblyFileVersion("7.0.0.0")] diff --git a/SAM.Picker/Properties/Resources.Designer.cs b/SAM.Picker/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5d42844 --- /dev/null +++ b/SAM.Picker/Properties/Resources.Designer.cs @@ -0,0 +1,91 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.1 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SAM.Picker.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SAM.Picker.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap Download { + get { + object obj = ResourceManager.GetObject("Download", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Filter { + get { + object obj = ResourceManager.GetObject("Filter", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Refresh { + get { + object obj = ResourceManager.GetObject("Refresh", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Search { + get { + object obj = ResourceManager.GetObject("Search", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/SAM.Picker/Properties/Resources.resx b/SAM.Picker/Properties/Resources.resx new file mode 100644 index 0000000..a406529 --- /dev/null +++ b/SAM.Picker/Properties/Resources.resx @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\arrow-circle-double.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\television-test.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\magnifier.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\download-cloud.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/SAM.Picker/Resources/arrow-circle-double.png b/SAM.Picker/Resources/arrow-circle-double.png new file mode 100644 index 0000000..ba5ebd1 Binary files /dev/null and b/SAM.Picker/Resources/arrow-circle-double.png differ diff --git a/SAM.Picker/Resources/download-cloud.png b/SAM.Picker/Resources/download-cloud.png new file mode 100644 index 0000000..ba0f492 Binary files /dev/null and b/SAM.Picker/Resources/download-cloud.png differ diff --git a/SAM.Picker/Resources/magnifier.png b/SAM.Picker/Resources/magnifier.png new file mode 100644 index 0000000..7a5ae62 Binary files /dev/null and b/SAM.Picker/Resources/magnifier.png differ diff --git a/SAM.Picker/Resources/television-test.png b/SAM.Picker/Resources/television-test.png new file mode 100644 index 0000000..fb0fdf0 Binary files /dev/null and b/SAM.Picker/Resources/television-test.png differ diff --git a/SAM.Picker/SAM.Picker.csproj b/SAM.Picker/SAM.Picker.csproj new file mode 100644 index 0000000..d2636d3 --- /dev/null +++ b/SAM.Picker/SAM.Picker.csproj @@ -0,0 +1,141 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E89E57BB-0F09-47F3-98A0-2026E2E65FBA} + WinExe + Properties + SAM.Picker + SAM.Picker + v3.5 + 512 + SAM.ico + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\bin\ + DEBUG;TRACE + prompt + 4 + x86 + AllRules.ruleset + + + none + true + ..\upload\ + TRACE + prompt + 4 + false + x86 + AllRules.ruleset + + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + Component + + + + Form + + + GamePicker.cs + + + + + GamePicker.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1} + SAM.API + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/SAM.Picker/SAM.Picker.csproj.DotSettings b/SAM.Picker/SAM.Picker.csproj.DotSettings new file mode 100644 index 0000000..6e7fff8 --- /dev/null +++ b/SAM.Picker/SAM.Picker.csproj.DotSettings @@ -0,0 +1,2 @@ + + No \ No newline at end of file diff --git a/SAM.Picker/SAM.ico b/SAM.Picker/SAM.ico new file mode 100644 index 0000000..899f6c9 Binary files /dev/null and b/SAM.Picker/SAM.ico differ diff --git a/SAM.sln b/SAM.sln new file mode 100644 index 0000000..3fbdcdb --- /dev/null +++ b/SAM.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAM.Picker", "SAM.Picker\SAM.Picker.csproj", "{E89E57BB-0F09-47F3-98A0-2026E2E65FBA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAM.API", "SAM.API\SAM.API.csproj", "{DF9102D5-048A-4D21-8CE3-3544CBDF0ED1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SAM.Game", "SAM.Game\SAM.Game.csproj", "{7640DE31-E54E-45F9-9CF0-8DF3A3EA30FC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E89E57BB-0F09-47F3-98A0-2026E2E65FBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E89E57BB-0F09-47F3-98A0-2026E2E65FBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E89E57BB-0F09-47F3-98A0-2026E2E65FBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E89E57BB-0F09-47F3-98A0-2026E2E65FBA}.Release|Any CPU.Build.0 = Release|Any CPU + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF9102D5-048A-4D21-8CE3-3544CBDF0ED1}.Release|Any CPU.Build.0 = Release|Any CPU + {7640DE31-E54E-45F9-9CF0-8DF3A3EA30FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7640DE31-E54E-45F9-9CF0-8DF3A3EA30FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7640DE31-E54E-45F9-9CF0-8DF3A3EA30FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7640DE31-E54E-45F9-9CF0-8DF3A3EA30FC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal