├── .gitignore ├── ArkData.Test ├── ArkData.Test.csproj ├── ArkDataAsync.cs ├── ArkDataSync.cs └── Properties │ └── AssemblyInfo.cs ├── ArkData.sln ├── ArkData ├── ArkData.csproj ├── ArkDataContainerAsync.cs ├── ArkDataContainerBase.cs ├── ArkDataContainerSync.cs ├── Extensions.cs ├── Helpers.cs ├── Models │ ├── SteamBan.cs │ ├── SteamPlayerResponse.cs │ ├── SteamProfile.cs │ └── SteamResponse.cs ├── Player.cs ├── PlayerParser.cs ├── Properties │ └── AssemblyInfo.cs ├── SSQLib │ ├── Packet.cs │ ├── PlayerInfo.cs │ ├── SSQL.cs │ ├── SSQLServerException.cs │ ├── ServerInfo.cs │ └── SocketUtils.cs ├── Tribe.cs ├── TribeParser.cs ├── bin │ ├── Debug │ │ └── Newtonsoft.Json.xml │ └── Release │ │ └── Newtonsoft.Json.xml ├── obj │ ├── Debug │ │ ├── ArkData.csproj.FileListAbsolute.txt │ │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs │ └── Release │ │ ├── ArkData.csproj.FileListAbsolute.txt │ │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs └── packages.config ├── LICENSE ├── README.md └── packages └── Newtonsoft.Json.7.0.1 ├── Newtonsoft.Json.7.0.1.nupkg ├── [Content_Types].xml ├── lib ├── net20 │ └── Newtonsoft.Json.xml ├── net35 │ └── Newtonsoft.Json.xml ├── net40 │ └── Newtonsoft.Json.xml ├── net45 │ └── Newtonsoft.Json.xml ├── portable-net40+sl5+wp80+win8+wpa81 │ └── Newtonsoft.Json.xml └── portable-net45+wp80+win8+wpa81+dnxcore50 │ └── Newtonsoft.Json.xml └── tools └── install.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | -------------------------------------------------------------------------------- /ArkData.Test/ArkData.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {28B89B00-034D-4FC1-B68B-9F0CD12625A3} 7 | Library 8 | Properties 9 | ArkData.Test 10 | ArkData.Test 11 | v4.5.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {d2ee1483-021f-4900-bbe8-88338d1386f4} 60 | ArkData 61 | 62 | 63 | 64 | 65 | 66 | 67 | False 68 | 69 | 70 | False 71 | 72 | 73 | False 74 | 75 | 76 | False 77 | 78 | 79 | 80 | 81 | 82 | 83 | 90 | -------------------------------------------------------------------------------- /ArkData.Test/ArkDataAsync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System.Threading.Tasks; 5 | 6 | namespace ArkData.Test 7 | { 8 | [TestClass] 9 | public class ArkDataAsync 10 | { 11 | private static ArkDataContainer container { get; set; } 12 | 13 | private const string Directory = "C:\\Users\\Admin\\Desktop\\ARK\\Tests"; 14 | private const string APIKey = "48756D53FA2E53CCEB292FA347258723"; 15 | private const string IP = "149.210.154.147"; 16 | private const int Port = 27015; 17 | 18 | [TestMethod] 19 | public async Task ParsePlayersAsync() 20 | { 21 | container = await ArkDataContainer.CreateAsync(Directory); 22 | 23 | Assert.IsTrue(container.Players.Count > 0); 24 | Assert.IsTrue(container.Tribes.Count > 0); 25 | } 26 | 27 | [TestMethod] 28 | public async Task LoadSteamAsync() 29 | { 30 | await container.LoadSteamAsync(APIKey); 31 | 32 | Assert.IsTrue(container.Players[0].SteamName != null); 33 | Assert.IsTrue(container.Players[0].SteamName != String.Empty); 34 | } 35 | 36 | [TestMethod] 37 | public async Task LoadOnlinePlayersAsync() 38 | { 39 | await container.LoadOnlinePlayersAsync(IP, Port); 40 | 41 | Assert.IsTrue(container.Players.Any(p => p.Online)); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ArkData.Test/ArkDataSync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | 5 | namespace ArkData.Test 6 | { 7 | [TestClass] 8 | public class ArkDataSync 9 | { 10 | private static ArkDataContainer container { get; set; } 11 | 12 | private const string Directory = "C:\\Users\\Admin\\Desktop\\ARK\\Tests"; 13 | private const string APIKey = "48756D53FA2E53CCEB292FA347258723"; 14 | private const string IP = "149.210.154.147"; 15 | private const int Port = 27015; 16 | 17 | [TestMethod] 18 | public void ParsePlayers() 19 | { 20 | container = ArkDataContainer.Create(Directory); 21 | 22 | Assert.IsTrue(container.Players.Count > 0); 23 | Assert.IsTrue(container.Tribes.Count > 0); 24 | } 25 | 26 | [TestMethod] 27 | public void LoadSteam() 28 | { 29 | container.LoadSteam(APIKey); 30 | 31 | Assert.IsTrue(container.Players[0].SteamName != null); 32 | Assert.IsTrue(container.Players[0].SteamName != String.Empty); 33 | } 34 | 35 | [TestMethod] 36 | public void LoadOnlinePlayers() 37 | { 38 | container.LoadOnlinePlayers(IP, Port); 39 | 40 | Assert.IsTrue(container.Players.Any(p => p.Online)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ArkData.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ArkData.Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ArkData.Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("28b89b00-034d-4fc1-b68b-9f0cd12625a3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ArkData.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.22823.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArkData", "ArkData\ArkData.csproj", "{D2EE1483-021F-4900-BBE8-88338D1386F4}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArkData.Test", "ArkData.Test\ArkData.Test.csproj", "{28B89B00-034D-4FC1-B68B-9F0CD12625A3}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D2EE1483-021F-4900-BBE8-88338D1386F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {D2EE1483-021F-4900-BBE8-88338D1386F4}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {D2EE1483-021F-4900-BBE8-88338D1386F4}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {D2EE1483-021F-4900-BBE8-88338D1386F4}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {28B89B00-034D-4FC1-B68B-9F0CD12625A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {28B89B00-034D-4FC1-B68B-9F0CD12625A3}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {28B89B00-034D-4FC1-B68B-9F0CD12625A3}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {28B89B00-034D-4FC1-B68B-9F0CD12625A3}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /ArkData/ArkData.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D2EE1483-021F-4900-BBE8-88338D1386F4} 8 | Library 9 | Properties 10 | ArkData 11 | ArkData 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | false 32 | 33 | 34 | true 35 | 36 | 37 | ArkDataKey.pfx 38 | 39 | 40 | 41 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll 42 | True 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 88 | -------------------------------------------------------------------------------- /ArkData/ArkDataContainerAsync.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ArkData 9 | { 10 | /// 11 | /// The container for the ARK data. 12 | /// 13 | public partial class ArkDataContainer 14 | { 15 | /// 16 | /// Loads the profile data for all users from the steam service 17 | /// 18 | /// The async task context. 19 | public async Task LoadSteamAsync(string apiKey) 20 | { 21 | var builder = new StringBuilder(); 22 | for (var i = 0; i < Players.Count; i++) 23 | builder.Append(Players[i].SteamId + ","); 24 | 25 | using (var client = new HttpClient()) 26 | { 27 | client.BaseAddress = new System.Uri("https://api.steampowered.com/"); 28 | client.DefaultRequestHeaders.Accept.Clear(); 29 | client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 30 | 31 | var response = await client.GetAsync(string.Format("ISteamUser/GetPlayerSummaries/v0002/?key={0}&steamids={1}", apiKey, builder.ToString())); 32 | if (response.IsSuccessStatusCode) 33 | using (var reader = new StreamReader(await response.Content.ReadAsStreamAsync())) 34 | { 35 | LinkSteamProfiles(await reader.ReadToEndAsync()); 36 | } 37 | else 38 | throw new System.Net.WebException("The Steam API request was unsuccessful. Are you using a valid key?"); 39 | 40 | response = await client.GetAsync(string.Format("ISteamUser/GetPlayerBans/v1/?key={0}&steamids={1}", apiKey, builder.ToString())); 41 | if (response.IsSuccessStatusCode) 42 | using (var reader = new StreamReader(await response.Content.ReadAsStreamAsync())) 43 | { 44 | LinkSteamBans(await reader.ReadToEndAsync()); 45 | } 46 | else 47 | throw new System.Net.WebException("The Steam API request was unsuccessful. Are you using a valid key?"); 48 | } 49 | SteamLoaded = true; 50 | } 51 | 52 | /// 53 | /// Fetches the player server status. Can only be done after fetching Steam player data. 54 | /// 55 | /// The IP of the server. 56 | /// The port of the server. 57 | /// The async task context. 58 | public Task LoadOnlinePlayersAsync(string ipString, int port) 59 | { 60 | if (SteamLoaded) 61 | return Task.Run(() => 62 | { 63 | LinkOnlinePlayers(ipString, port); 64 | }); 65 | else 66 | throw new System.Exception("The Steam user data should be loaded before the server status can be checked."); 67 | } 68 | 69 | /// 70 | /// Instantiates the ArkDataContainer and parses all the user-data files 71 | /// 72 | /// The directory containing the profile and tribe files. 73 | /// The async task context containing the resulting container. 74 | public static async Task CreateAsync(string directory) 75 | { 76 | if (!Directory.Exists(directory)) 77 | throw new DirectoryNotFoundException("The ARK data directory couldn't be found."); 78 | 79 | var playerFiles = Directory.GetFiles(directory).Where(p => p.ToLower().Contains(".arkprofile")).ToArray(); 80 | var tribeFiles = Directory.GetFiles(directory).Where(p => p.ToLower().Contains(".arktribe")).ToArray(); 81 | 82 | if (playerFiles.Length == 0 && tribeFiles.Length == 0) 83 | throw new FileLoadException("The directory did not contain any of the parseable files."); 84 | 85 | var container = new ArkDataContainer(); 86 | 87 | for (var i = 0; i < playerFiles.Length; i++) 88 | container.Players.Add(await Parser.ParsePlayerAsync(playerFiles[i])); 89 | 90 | for (var i = 0; i < tribeFiles.Length; i++) 91 | container.Tribes.Add(await Parser.ParseTribeAsync(tribeFiles[i])); 92 | 93 | container.LinkPlayerTribe(); 94 | 95 | return container; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ArkData/ArkDataContainerBase.cs: -------------------------------------------------------------------------------- 1 | using SSQLib; 2 | using System.Net; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | using Newtonsoft.Json; 6 | using System.Runtime.Remoting; 7 | 8 | /// 9 | /// The container for the ARK data. 10 | /// 11 | namespace ArkData 12 | { 13 | public partial class ArkDataContainer 14 | { 15 | /// 16 | /// A list of all players registered on the server. 17 | /// 18 | public List Players { get; set; } 19 | /// 20 | /// A list of all tribes registered on the server. 21 | /// 22 | public List Tribes { get; set; } 23 | /// 24 | /// Indicates whether the steam user data has been loaded. 25 | /// 26 | private bool SteamLoaded { get; set; } 27 | 28 | /// 29 | /// Constructs the ArkDataContainer. 30 | /// 31 | public ArkDataContainer() 32 | { 33 | Players = new List(); 34 | Tribes = new List(); 35 | SteamLoaded = false; 36 | } 37 | 38 | /// 39 | /// Links the online players, to the ARK player profiles. 40 | /// 41 | /// The server ip address. 42 | /// The Steam query port. 43 | private void LinkOnlinePlayers(string ipString, int port) 44 | { 45 | try 46 | { 47 | var online = Enumerable.OfType(new SSQL().Players(new IPEndPoint(IPAddress.Parse(ipString), port))).ToList(); 48 | 49 | for (var i = 0; i < Players.Count; i++) 50 | { 51 | var online_player = online.SingleOrDefault(p => p.Name == Players[i].SteamName); 52 | if (online_player != null) 53 | Players[i].Online = true; 54 | else 55 | Players[i].Online = false; 56 | } 57 | } catch(SSQLServerException ex) 58 | { 59 | throw new ServerException("The connection to the ARK server failed. Please check the configured IP address and port."); 60 | } 61 | } 62 | 63 | /// 64 | /// Links the players to their tribes and the tribes to the players. 65 | /// 66 | private void LinkPlayerTribe() 67 | { 68 | for (var i = 0; i < Players.Count; i++) 69 | { 70 | var player = Players[i]; 71 | player.OwnedTribes = Tribes.Where(t => t.OwnerId == player.Id).ToList(); 72 | player.Tribe = Tribes.SingleOrDefault(t => t.Id == player.TribeId); 73 | } 74 | 75 | for (var i = 0; i < Tribes.Count; i++) 76 | { 77 | var tribe = Tribes[i]; 78 | tribe.Owner = Players.SingleOrDefault(p => p.Id == tribe.OwnerId); 79 | tribe.Players = Players.Where(p => p.TribeId == tribe.Id).ToList(); 80 | } 81 | } 82 | 83 | /// 84 | /// Deserializes JSON from Steam API and links Steam profile to ARK profile. 85 | /// 86 | /// The JSON data string. 87 | private void LinkSteamProfiles(string jsonString) 88 | { 89 | var profiles = JsonConvert.DeserializeObject>(jsonString).response.players; 90 | 91 | for (var i = 0; i < profiles.Count; i++) 92 | { 93 | var player = Players.Single(p => p.SteamId == profiles[i].steamid); 94 | player.SteamName = profiles[i].personaname; 95 | player.ProfileUrl = profiles[i].profileurl; 96 | player.AvatarUrl = profiles[i].avatar; 97 | } 98 | } 99 | 100 | /// 101 | /// Deserializes JSON from Steam API and links Steam ban data to ARK profile. 102 | /// 103 | /// The JSON data string. 104 | private void LinkSteamBans(string jsonString) 105 | { 106 | var bans = JsonConvert.DeserializeObject>(jsonString).players; 107 | for (var i = 0; i < bans.Count; i++) 108 | { 109 | var player = Players.Single(p => p.SteamId == bans[i].SteamId); 110 | player.CommunityBanned = bans[i].CommunityBanned; 111 | player.VACBanned = bans[i].VACBanned; 112 | player.NumberOfVACBans = bans[i].NumberOfVACBans; 113 | player.NumberOfGameBans = bans[i].NumberOfGameBans; 114 | player.DaysSinceLastBan = bans[i].DaysSinceLastBan; 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /ArkData/ArkDataContainerSync.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Text; 6 | 7 | namespace ArkData 8 | { 9 | /// 10 | /// The container for the ARK data. 11 | /// 12 | public partial class ArkDataContainer 13 | { 14 | /// 15 | /// Loads the profile data for all users from the steam service 16 | /// 17 | /// The Steam API key 18 | public void LoadSteam(string apiKey) 19 | { 20 | var builder = new StringBuilder(); 21 | for (var i = 0; i < Players.Count; i++) 22 | builder.Append(Players[i].SteamId + ","); 23 | 24 | using (var client = new HttpClient()) 25 | { 26 | client.BaseAddress = new System.Uri("https://api.steampowered.com/"); 27 | client.DefaultRequestHeaders.Accept.Clear(); 28 | client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 29 | 30 | var response = client.GetAsync(string.Format("ISteamUser/GetPlayerSummaries/v0002/?key={0}&steamids={1}", apiKey, builder.ToString())).Result; 31 | if (response.IsSuccessStatusCode) 32 | using (var reader = new StreamReader(response.Content.ReadAsStreamAsync().Result)) 33 | { 34 | LinkSteamProfiles(reader.ReadToEnd()); 35 | } 36 | else 37 | throw new System.Net.WebException("The Steam API request was unsuccessful. Are you using a valid key?"); 38 | 39 | response = client.GetAsync(string.Format("ISteamUser/GetPlayerBans/v1/?key={0}&steamids={1}", apiKey, builder.ToString())).Result; 40 | if (response.IsSuccessStatusCode) 41 | using (var reader = new StreamReader(response.Content.ReadAsStreamAsync().Result)) 42 | { 43 | LinkSteamBans(reader.ReadToEnd()); 44 | } 45 | else 46 | throw new System.Net.WebException("The Steam API request was unsuccessful. Are you using a valid key?"); 47 | } 48 | SteamLoaded = true; 49 | } 50 | 51 | /// 52 | /// Fetches the player server status. Can only be done after fetching Steam player data. 53 | /// 54 | /// The IP of the server. 55 | /// The port of the server. 56 | public void LoadOnlinePlayers(string ipString, int port) 57 | { 58 | if (SteamLoaded) 59 | { 60 | LinkOnlinePlayers(ipString, port); 61 | } 62 | else 63 | throw new System.Exception("The Steam user data should be loaded before the server status can be checked."); 64 | } 65 | 66 | /// 67 | /// Instantiates the ArkDataContainer and parses all the user data files 68 | /// 69 | /// The directory containing the profile and tribe files. 70 | public static ArkDataContainer Create(string directory) 71 | { 72 | if (!Directory.Exists(directory)) 73 | throw new DirectoryNotFoundException("The ARK data directory couldn't be found."); 74 | 75 | var playerFiles = Directory.GetFiles(directory).Where(p => p.ToLower().Contains(".arkprofile")).ToArray(); 76 | var tribeFiles = Directory.GetFiles(directory).Where(p => p.ToLower().Contains(".arktribe")).ToArray(); 77 | 78 | if (playerFiles.Length == 0 && tribeFiles.Length == 0) 79 | throw new FileLoadException("The directory did not contain any of the parseable files."); 80 | 81 | var container = new ArkDataContainer(); 82 | 83 | for (var i = 0; i < playerFiles.Length; i++) 84 | container.Players.Add(Parser.ParsePlayer(playerFiles[i])); 85 | 86 | for (var i = 0; i < tribeFiles.Length; i++) 87 | container.Tribes.Add(Parser.ParseTribe(tribeFiles[i])); 88 | 89 | container.LinkPlayerTribe(); 90 | 91 | return container; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /ArkData/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ArkData 4 | { 5 | internal static class Extensions 6 | { 7 | private static readonly int[] Empty = new int[0]; 8 | 9 | public static int LocateFirst(this byte[] self, byte[] candidate, int offset = 0) 10 | { 11 | if (IsEmptyLocate(self, candidate, offset)) 12 | return -1; 13 | 14 | for (int position = offset; position < self.Length; position++) 15 | if (IsMatch(self, position, candidate)) 16 | return position; 17 | 18 | return -1; 19 | } 20 | 21 | public static int[] Locate(this byte[] self, byte[] candidate) 22 | { 23 | if (IsEmptyLocate(self, candidate, 0)) 24 | return Empty; 25 | 26 | List list = new List(); 27 | for (int position = 0; position < self.Length; ++position) 28 | if (IsMatch(self, position, candidate)) 29 | list.Add(position); 30 | 31 | if (list.Count != 0) 32 | return list.ToArray(); 33 | 34 | return Empty; 35 | } 36 | 37 | private static bool IsMatch(byte[] array, int position, byte[] candidate) 38 | { 39 | if (candidate.Length > array.Length - position) 40 | return false; 41 | 42 | for (int index = 0; index < candidate.Length; ++index) 43 | if ((array[position + index] != candidate[index])) 44 | return false; 45 | 46 | return true; 47 | } 48 | 49 | private static bool IsEmptyLocate(byte[] array, byte[] candidate, int offset) 50 | { 51 | if (array != null && candidate != null && 52 | (array.Length != 0 && candidate.Length != 0) && 53 | (candidate.Length <= array.Length && offset != -1)) 54 | return offset > array.Length; 55 | return true; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ArkData/Helpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace ArkData 5 | { 6 | internal class Helpers 7 | { 8 | public static int GetInt(byte[] data, string name) 9 | { 10 | byte[] bytes1 = Encoding.Default.GetBytes(name); 11 | byte[] bytes2 = Encoding.Default.GetBytes("IntProperty"); 12 | 13 | int offset = data.LocateFirst(bytes1, 0); 14 | int num = data.LocateFirst(bytes2, offset); 15 | 16 | if (num > -1) 17 | return BitConverter.ToInt32(data, num + bytes2.Length + 9); 18 | return -1; 19 | } 20 | 21 | public static ushort GetUInt16(byte[] data, string name) 22 | { 23 | byte[] bytes1 = Encoding.Default.GetBytes(name); 24 | byte[] bytes2 = Encoding.Default.GetBytes("UInt16Property"); 25 | 26 | int offset = data.LocateFirst(bytes1, 0); 27 | int num = data.LocateFirst(bytes2, offset); 28 | 29 | if (num >= 0) 30 | return BitConverter.ToUInt16(data, num + bytes2.Length + 9); 31 | return 0; 32 | } 33 | 34 | public static string GetString(byte[] data, string name) 35 | { 36 | byte[] bytes1 = Encoding.Default.GetBytes(name); 37 | byte[] bytes2 = Encoding.Default.GetBytes("StrProperty"); 38 | int offset = data.LocateFirst(bytes1, 0); 39 | int num = data.LocateFirst(bytes2, offset); 40 | 41 | if (num < 0) 42 | return string.Empty; 43 | 44 | byte[] numArray = new byte[1]; 45 | 46 | Array.Copy(data, num + bytes2.Length + 1, numArray, 0, 1); 47 | 48 | int length = (int)numArray[0] - (data[num + bytes2.Length + 12] == byte.MaxValue ? 6 : 5); 49 | 50 | byte[] bytes3 = new byte[length]; 51 | Array.Copy(data, num + bytes2.Length + 13, bytes3, 0, length); 52 | 53 | if (data[num + bytes2.Length + 12] == byte.MaxValue) 54 | return Encoding.Unicode.GetString(bytes3); 55 | 56 | return Encoding.Default.GetString(bytes3); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ArkData/Models/SteamBan.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ArkData.Models 8 | { 9 | internal class SteamBan 10 | { 11 | public string SteamId { get; set; } 12 | public bool CommunityBanned { get; set; } 13 | public bool VACBanned { get; set; } 14 | public int NumberOfVACBans { get; set; } 15 | public int DaysSinceLastBan { get; set; } 16 | public int NumberOfGameBans { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ArkData/Models/SteamPlayerResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ArkData.Models 8 | { 9 | internal class SteamPlayerResponse 10 | { 11 | public List players { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ArkData/Models/SteamProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ArkData.Models 8 | { 9 | internal class SteamProfile 10 | { 11 | public string steamid { get; set; } 12 | public string personaname { get; set; } 13 | public string profileurl { get; set; } 14 | public string avatar { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ArkData/Models/SteamResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ArkData.Models 8 | { 9 | internal class SteamResponse 10 | { 11 | public SteamPlayerResponse response { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ArkData/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ArkData 5 | { 6 | public class Player 7 | { 8 | public long Id { get; set; } 9 | public string SteamId { get; set; } 10 | public string SteamName { get; set; } 11 | public string AvatarUrl { get; set; } 12 | public string CharacterName { get; set; } 13 | public bool Online { get; set; } 14 | public DateTime FileCreated { get; set; } 15 | public DateTime FileUpdated { get; set; } 16 | public int? TribeId { get; set; } 17 | public short Level { get; set; } 18 | public string ProfileUrl { get; set; } 19 | public bool CommunityBanned { get; set; } 20 | public bool VACBanned { get; set; } 21 | public int NumberOfVACBans { get; set; } 22 | public int DaysSinceLastBan { get; set; } 23 | public int NumberOfGameBans { get; set; } 24 | public virtual Tribe Tribe { get; set; } 25 | public virtual List OwnedTribes { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ArkData/PlayerParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | 6 | namespace ArkData 7 | { 8 | internal partial class Parser 9 | { 10 | private static ulong GetId(byte[] data) 11 | { 12 | byte[] bytes1 = Encoding.Default.GetBytes("PlayerDataID"); 13 | byte[] bytes2 = Encoding.Default.GetBytes("UInt64Property"); 14 | int offset = Extensions.LocateFirst(data, bytes1, 0); 15 | int num = Extensions.LocateFirst(data, bytes2, offset); 16 | 17 | return BitConverter.ToUInt64(data, num + bytes2.Length + 9); 18 | } 19 | 20 | private static string GetSteamId(byte[] data) 21 | { 22 | byte[] bytes1 = Encoding.Default.GetBytes("UniqueNetIdRepl"); 23 | int num = Extensions.LocateFirst(data, bytes1, 0); 24 | byte[] bytes2 = new byte[17]; 25 | 26 | Array.Copy((Array)data, num + bytes1.Length + 9, (Array)bytes2, 0, 17); 27 | return Encoding.Default.GetString(bytes2); 28 | } 29 | 30 | public static Player ParsePlayer(string fileName) 31 | { 32 | FileInfo fileInfo = new FileInfo(fileName); 33 | if (!fileInfo.Exists) 34 | return null; 35 | byte[] data = File.ReadAllBytes(fileName); 36 | 37 | return new Player() 38 | { 39 | Id = Convert.ToInt64(GetId(data)), 40 | SteamId = GetSteamId(data), 41 | SteamName = Helpers.GetString(data, "PlayerName"), 42 | CharacterName = Helpers.GetString(data, "PlayerCharacterName"), 43 | TribeId = Helpers.GetInt(data, "TribeID"), 44 | Level = (short)(1 + Convert.ToInt32(Helpers.GetUInt16(data, "CharacterStatusComponent_ExtraCharacterLevel"))), 45 | 46 | FileCreated = fileInfo.CreationTime, 47 | FileUpdated = fileInfo.LastWriteTime 48 | }; 49 | } 50 | 51 | public static Task ParsePlayerAsync(string fileName) 52 | { 53 | return Task.Run(() => 54 | { 55 | return ParsePlayer(fileName); 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ArkData/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ArkData SDK")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("AuthiQ")] 12 | [assembly: AssemblyProduct("ArkData SDK")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(true)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d2ee1483-021f-4900-bbe8-88338d1386f4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.3.0")] 36 | [assembly: AssemblyFileVersion("1.0.3.0")] 37 | -------------------------------------------------------------------------------- /ArkData/SSQLib/Packet.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of SSQLib. 3 | * 4 | * SSQLib is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Lesser General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * SSQLib is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with SSQLib. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.IO; 23 | 24 | namespace SSQLib 25 | { 26 | internal class Packet 27 | { 28 | internal int RequestId = 0; 29 | internal string Data = ""; 30 | 31 | internal Packet() { } 32 | 33 | //Output the packet data as a byte array 34 | internal byte[] outputAsBytes() 35 | { 36 | byte[] data_byte = null; 37 | 38 | if (Data.Length > 0) 39 | { 40 | //Create a new packet based on the length of the request 41 | data_byte = new byte[Data.Length + 5]; 42 | 43 | //Fill the first 4 bytes with 0xff 44 | data_byte[0] = 0xff; 45 | data_byte[1] = 0xff; 46 | data_byte[2] = 0xff; 47 | data_byte[3] = 0xff; 48 | 49 | //Copy the data to the new request 50 | Array.Copy(ASCIIEncoding.UTF8.GetBytes(Data), 0, data_byte, 4, Data.Length); 51 | } 52 | //Empty request to get challenge 53 | else 54 | { 55 | data_byte = new byte[5]; 56 | 57 | //Fill the first 4 bytes with 0xff 58 | data_byte[0] = 0xff; 59 | data_byte[1] = 0xff; 60 | data_byte[2] = 0xff; 61 | data_byte[3] = 0xff; 62 | data_byte[4] = 0x57; 63 | } 64 | 65 | 66 | return data_byte; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ArkData/SSQLib/PlayerInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of SSQLib. 3 | * 4 | * SSQLib is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Lesser General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * SSQLib is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with SSQLib. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | 23 | namespace SSQLib 24 | { 25 | /// 26 | /// Stores information about a player in the server 27 | /// 28 | public class PlayerInfo 29 | { 30 | private string name = ""; 31 | private int index = -9999; 32 | private int kills = -9999; 33 | private int deaths = -9999; 34 | private int score = -9999; 35 | private int ping = -9999; 36 | private int rate = -9999; 37 | private float time = 0.0f; 38 | 39 | /// 40 | /// Creates a new PlayerInfo object with default values 41 | /// 42 | public PlayerInfo() { } 43 | 44 | /// 45 | /// The name of the player 46 | /// 47 | public string Name 48 | { 49 | get 50 | { 51 | return this.name; 52 | } 53 | 54 | set 55 | { 56 | this.name = value; 57 | } 58 | } 59 | 60 | /// 61 | /// The amount of kills the player has (default: -9999) 62 | /// 63 | public int Kills 64 | { 65 | get { 66 | return this.kills; 67 | } 68 | 69 | set { 70 | this.kills = value; 71 | } 72 | } 73 | 74 | /// 75 | /// The amount of deaths the player has (default: -9999) 76 | /// 77 | public int Deaths 78 | { 79 | get 80 | { 81 | return this.deaths; 82 | } 83 | 84 | set 85 | { 86 | this.deaths = value; 87 | } 88 | } 89 | 90 | /// 91 | /// The score of the player (default: -9999) 92 | /// 93 | public int Score 94 | { 95 | get 96 | { 97 | return this.score; 98 | } 99 | 100 | set 101 | { 102 | this.score = value; 103 | } 104 | } 105 | 106 | /// 107 | /// The ping of the player (default: -9999) 108 | /// 109 | public int Ping 110 | { 111 | get 112 | { 113 | return this.ping; 114 | } 115 | 116 | set 117 | { 118 | this.ping = value; 119 | } 120 | } 121 | 122 | /// 123 | /// The rate(?) of the player (default: -9999) 124 | /// 125 | public int Rate 126 | { 127 | get 128 | { 129 | return this.rate; 130 | } 131 | 132 | set 133 | { 134 | this.rate = value; 135 | } 136 | } 137 | 138 | /// 139 | /// The index of the player in the server 140 | /// 141 | public int Index 142 | { 143 | get 144 | { 145 | return this.index; 146 | } 147 | 148 | set 149 | { 150 | this.index = value; 151 | } 152 | } 153 | 154 | /// 155 | /// The time the player has been in the server 156 | /// 157 | public float Time 158 | { 159 | get 160 | { 161 | return this.time; 162 | } 163 | 164 | set 165 | { 166 | this.time = value; 167 | } 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /ArkData/SSQLib/SSQL.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of SSQLib. 3 | * 4 | * SSQLib is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Lesser General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * SSQLib is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with SSQLib. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Net; 23 | using System.Collections; 24 | 25 | namespace SSQLib 26 | { 27 | /// 28 | /// Used to retreive information from a Source server 29 | /// 30 | public class SSQL 31 | { 32 | /// 33 | /// Generates an SSQL object with default values 34 | /// 35 | public SSQL() 36 | { 37 | 38 | } 39 | /// 40 | /// Pings the specified Source server to retreive information about it such as the server name, max players, current number of players, etc. 41 | /// 42 | /// The IPEndPoint object containing the IP address and port of the server 43 | /// Information about the server or throws an SSQLServerException if it could not be retreived 44 | public ServerInfo Server(IPEndPoint ip_end) 45 | { 46 | //Create a new empty server info object 47 | ServerInfo info = new ServerInfo(); 48 | 49 | //Create an empty buffer 50 | byte[] buf = null; 51 | 52 | //Create a new packet and request 53 | Packet requestPacket = new Packet(); 54 | requestPacket.Data = "TSource Engine Query"; 55 | 56 | try 57 | { 58 | //Attempt to get the server info 59 | buf = SocketUtils.getInfo(ip_end, requestPacket); 60 | } 61 | catch(SSQLServerException e) 62 | { 63 | throw e; 64 | } 65 | 66 | //Start past the first four bytes which are all 0xff 67 | int i = 4; 68 | 69 | //Make sure the first character is an I 70 | if (buf[i++] != 'I') return null; 71 | 72 | //Make sure the returned version is above 0x07 73 | if (buf[i++] < 0x07) return null; 74 | 75 | StringBuilder srvName = new StringBuilder(); 76 | 77 | //Retrieve the server name 78 | while (buf[i] != 0x00) 79 | { 80 | srvName.Append((char)buf[i]); 81 | i++; 82 | } 83 | 84 | //Move to the next byte 85 | i++; 86 | 87 | //Set the name of the server 88 | info.Name = srvName.ToString(); 89 | 90 | StringBuilder mapName = new StringBuilder(); 91 | 92 | //Retrieve the map name 93 | while (buf[i] != 0x00) 94 | { 95 | mapName.Append((char)buf[i]); 96 | i++; 97 | } 98 | 99 | //Move to the next byte 100 | i++; 101 | 102 | info.Map = mapName.ToString(); 103 | 104 | StringBuilder gameName = new StringBuilder(); 105 | 106 | //Get the short name for the game 107 | while (buf[i] != 0x00) 108 | { 109 | gameName.Append((char)buf[i]); 110 | i++; 111 | } 112 | 113 | //Move to the next byte 114 | i++; 115 | 116 | StringBuilder gameFriendly = new StringBuilder(); 117 | 118 | //Get the friendly game description 119 | while (buf[i] != 0x00) 120 | { 121 | gameFriendly.Append((char)buf[i]); 122 | i++; 123 | } 124 | 125 | //Move to the next byte 126 | i++; 127 | 128 | info.Game = gameFriendly.ToString() + " (" + gameName.ToString() + ")"; 129 | 130 | short appID = (short)System.BitConverter.ToInt16(buf, i); 131 | 132 | //Skip the next 2 bytes 133 | i += 2; 134 | 135 | //Store the app id 136 | info.AppID = appID.ToString(); 137 | 138 | //Get the number of players 139 | info.PlayerCount = buf[i++].ToString(); 140 | 141 | //Get the number of max players 142 | info.MaxPlayers = buf[i++].ToString(); 143 | 144 | //Get the number of bots 145 | info.BotCount = buf[i++].ToString(); 146 | 147 | //Get the dedicated server type 148 | if ((char)buf[i] == 'l') 149 | info.Dedicated = ServerInfo.DedicatedType.LISTEN; 150 | else if ((char)buf[i] == 'd') 151 | info.Dedicated = ServerInfo.DedicatedType.DEDICATED; 152 | else if ((char)buf[i] == 'p') 153 | info.Dedicated = ServerInfo.DedicatedType.SOURCETV; 154 | 155 | //Move to the next byte 156 | i++; 157 | 158 | //Get the OS type 159 | if ((char)buf[i] == 'l') 160 | info.OS = ServerInfo.OSType.LINUX; 161 | else if ((char)buf[i] == 'w') 162 | info.OS = ServerInfo.OSType.WINDOWS; 163 | 164 | //Move to the next byte 165 | i++; 166 | 167 | //Check for password protection 168 | if (buf[i++] == 0x01) info.Password = true; 169 | 170 | //Check for VAC 171 | if (buf[i++] == 0x01) info.VAC = true; 172 | 173 | StringBuilder versionInfo = new StringBuilder(); 174 | 175 | //Get the game version 176 | while (buf[i] != 0x00) 177 | { 178 | versionInfo.Append((char)buf[i]); 179 | i++; 180 | } 181 | 182 | //Move to the next byte 183 | i++; 184 | 185 | //Set the version 186 | info.Version = versionInfo.ToString(); 187 | 188 | return info; 189 | } 190 | 191 | /// 192 | /// Retreives information about the players on a Source server 193 | /// 194 | /// The IPEndPoint object storing the IP address and port of the server 195 | /// An ArrayList of PlayerInfo or throws an SSQLServerException if the server could not be reached 196 | public ArrayList Players(IPEndPoint ip_end) 197 | { 198 | //Create a new array list to store the player array 199 | ArrayList players = new ArrayList(); 200 | 201 | //Create a new buffer to receive packets 202 | byte[] buf = null; 203 | 204 | //Create a challenge packet 205 | byte[] challenge = new byte[9]; 206 | challenge[0] = (byte)0xff; 207 | challenge[1] = (byte)0xff; 208 | challenge[2] = (byte)0xff; 209 | challenge[3] = (byte)0xff; 210 | challenge[4] = (byte)0x55; 211 | challenge[5] = (byte)0x00; 212 | challenge[6] = (byte)0x00; 213 | challenge[7] = (byte)0x00; 214 | challenge[8] = (byte)0x00; 215 | 216 | try 217 | { 218 | //Attempt to get the challenge response 219 | buf = SocketUtils.getInfo(ip_end, challenge); 220 | } 221 | catch (SSQLServerException e) 222 | { 223 | throw e; 224 | } 225 | 226 | int i = 4; 227 | 228 | //Make sure the response starts with A 229 | if (buf[i++] != 'A') return null; 230 | 231 | //Create the new request with the challenge number 232 | byte[] requestPlayer = new byte[9]; 233 | 234 | requestPlayer[0] = (byte)0xff; 235 | requestPlayer[1] = (byte)0xff; 236 | requestPlayer[2] = (byte)0xff; 237 | requestPlayer[3] = (byte)0xff; 238 | requestPlayer[4] = (byte)0x55; 239 | requestPlayer[5] = buf[i++]; 240 | requestPlayer[6] = buf[i++]; 241 | requestPlayer[7] = buf[i++]; 242 | requestPlayer[8] = buf[i++]; 243 | 244 | try 245 | { 246 | //Attempt to get the players response 247 | buf = SocketUtils.getInfo(ip_end, requestPlayer); 248 | } 249 | catch (SSQLServerException) 250 | { 251 | return null; 252 | } 253 | 254 | //Start past 0xffffffff 255 | i = 4; 256 | 257 | //Make sure the response starts with D 258 | if (buf[i++] != 'D') return null; 259 | 260 | //Get the amount of players 261 | byte numPlayers = buf[i++]; 262 | 263 | //Loop through each player and extract their stats 264 | for (int ii = 0; ii < numPlayers; ii++) 265 | { 266 | //Create a new player 267 | PlayerInfo newPlayer = new PlayerInfo(); 268 | 269 | //Set the index of the player (Does not work in L4D2, always returns 0) 270 | newPlayer.Index = buf[i++]; 271 | 272 | //Create a new player name 273 | List playerName = new List(); 274 | 275 | //Loop through and store the player's name 276 | while (buf[i] != 0x00) 277 | { 278 | playerName.Add(buf[i++]); 279 | } 280 | 281 | //Move past the end of the string 282 | i++; 283 | 284 | // Decode the player name 285 | newPlayer.Name = Encoding.UTF8.GetString(playerName.ToArray()); 286 | 287 | //Get the kills and store them in the player info 288 | newPlayer.Kills = (int)(buf[i] & 255) | ((buf[i + 1] & 255) << 8) | ((buf[i + 2] & 255) << 16) | ((buf[i + 3] & 255) << 24); 289 | 290 | //Move to the next item 291 | i += 5; 292 | 293 | //Get the time connected as a float and store it in the player info 294 | newPlayer.Time = (float)((int)(buf[i] & 255) | ((buf[i + 1] & 255) << 8)); 295 | 296 | //Move past the float 297 | i += 3; 298 | 299 | //Add the player to the list 300 | players.Add(newPlayer); 301 | } 302 | 303 | //Return the list of players 304 | return players; 305 | } 306 | } 307 | } 308 | -------------------------------------------------------------------------------- /ArkData/SSQLib/SSQLServerException.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of SSQLib. 3 | * 4 | * SSQLib is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Lesser General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * SSQLib is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with SSQLib. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | 23 | namespace SSQLib 24 | { 25 | class SSQLServerException : System.Exception 26 | { 27 | public SSQLServerException(string message) : base(message) 28 | { 29 | 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ArkData/SSQLib/ServerInfo.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of SSQLib. 3 | * 4 | * SSQLib is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Lesser General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * SSQLib is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with SSQLib. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | 23 | namespace SSQLib 24 | { 25 | /// 26 | /// Stores information about the Source server 27 | /// 28 | public class ServerInfo 29 | { 30 | private string name = ""; 31 | private string ip = ""; 32 | private string port = ""; 33 | private string game = ""; 34 | private string gameVersion = ""; 35 | private string appID = ""; 36 | private string map = ""; 37 | private string playerCount = ""; 38 | private string botCount = ""; 39 | private string maxPlayers = ""; 40 | 41 | private bool passworded = false; 42 | private bool vac = false; 43 | private ServerInfo.DedicatedType dedicated = ServerInfo.DedicatedType.NONE; 44 | private ServerInfo.OSType os = ServerInfo.OSType.NONE; 45 | 46 | /// 47 | /// Creates a new object with default values 48 | /// 49 | public ServerInfo() { } 50 | 51 | /// 52 | /// The name of the server 53 | /// 54 | public string Name 55 | { 56 | get 57 | { 58 | return this.name; 59 | } 60 | 61 | set 62 | { 63 | this.name = value; 64 | } 65 | } 66 | 67 | /// 68 | /// The IP address of the server 69 | /// 70 | public string IP 71 | { 72 | get 73 | { 74 | return this.ip; 75 | } 76 | 77 | set 78 | { 79 | this.ip = value; 80 | } 81 | } 82 | 83 | /// 84 | /// The port the server uses 85 | /// 86 | public string Port 87 | { 88 | get 89 | { 90 | return this.port; 91 | } 92 | 93 | set 94 | { 95 | this.port = value; 96 | } 97 | } 98 | 99 | /// 100 | /// The game being played on the server (i.e. Team Fortress (tf)) 101 | /// 102 | public string Game 103 | { 104 | get 105 | { 106 | return this.game; 107 | } 108 | 109 | set 110 | { 111 | this.game = value; 112 | } 113 | } 114 | 115 | /// 116 | /// The game version running on the server 117 | /// 118 | public string Version 119 | { 120 | get 121 | { 122 | return this.gameVersion; 123 | } 124 | 125 | set 126 | { 127 | this.gameVersion = value; 128 | } 129 | } 130 | 131 | /// 132 | /// The map currently being played on the server 133 | /// 134 | public string Map 135 | { 136 | get 137 | { 138 | return this.map; 139 | } 140 | 141 | set 142 | { 143 | this.map = value; 144 | } 145 | } 146 | 147 | /// 148 | /// The current player count on the server 149 | /// 150 | public string PlayerCount 151 | { 152 | get 153 | { 154 | return this.playerCount; 155 | } 156 | 157 | set 158 | { 159 | this.playerCount = value; 160 | } 161 | } 162 | 163 | /// 164 | /// The current bot count on the server 165 | /// 166 | public string BotCount 167 | { 168 | get 169 | { 170 | return this.botCount; 171 | } 172 | 173 | set 174 | { 175 | this.botCount = value; 176 | } 177 | } 178 | 179 | /// 180 | /// The max amount of players allowed on the server 181 | /// 182 | public string MaxPlayers 183 | { 184 | get 185 | { 186 | return this.maxPlayers; 187 | } 188 | 189 | set 190 | { 191 | this.maxPlayers = value; 192 | } 193 | } 194 | 195 | /// 196 | /// Stores whether the server is passworded or not 197 | /// 198 | public bool Password 199 | { 200 | get 201 | { 202 | return this.passworded; 203 | } 204 | 205 | set 206 | { 207 | this.passworded = value; 208 | } 209 | } 210 | 211 | /// 212 | /// Stores whether the server is VAC protected or not 213 | /// 214 | public bool VAC 215 | { 216 | get 217 | { 218 | return this.vac; 219 | } 220 | 221 | set 222 | { 223 | this.vac = value; 224 | } 225 | } 226 | 227 | /// 228 | /// Stores the app ID of the game used by the server 229 | /// 230 | public string AppID 231 | { 232 | get 233 | { 234 | return this.appID; 235 | } 236 | 237 | set 238 | { 239 | this.appID = value; 240 | } 241 | } 242 | 243 | /// 244 | /// Stores the type of server running (Listen, Dedicated, SourceTV) 245 | /// 246 | public ServerInfo.DedicatedType Dedicated 247 | { 248 | get 249 | { 250 | return this.dedicated; 251 | } 252 | 253 | set 254 | { 255 | this.dedicated = value; 256 | } 257 | } 258 | 259 | /// 260 | /// Stores the operating system of the server (Windows, Linux) 261 | /// 262 | public ServerInfo.OSType OS 263 | { 264 | get 265 | { 266 | return this.os; 267 | } 268 | 269 | set 270 | { 271 | this.os = value; 272 | } 273 | } 274 | 275 | /// 276 | /// Used to describe the type of server running 277 | /// 278 | public enum DedicatedType 279 | { 280 | /// 281 | /// Default value 282 | /// 283 | NONE, 284 | /// 285 | /// Listen server (locally hosted) 286 | /// 287 | LISTEN, 288 | /// 289 | /// Dedicated server 290 | /// 291 | DEDICATED, 292 | /// 293 | /// SourceTV server 294 | /// 295 | SOURCETV 296 | }; 297 | 298 | /// 299 | /// Used to describe the operating system running on the server 300 | /// 301 | public enum OSType 302 | { 303 | /// 304 | /// Default value 305 | /// 306 | NONE, 307 | /// 308 | /// Windows server 309 | /// 310 | WINDOWS, 311 | /// 312 | /// Linux server 313 | /// 314 | LINUX 315 | }; 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /ArkData/SSQLib/SocketUtils.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of SSQLib. 3 | * 4 | * SSQLib is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Lesser General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * SSQLib is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public License 15 | * along with SSQLib. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Net; 23 | using System.Net.Sockets; 24 | 25 | namespace SSQLib 26 | { 27 | internal class SocketUtils 28 | { 29 | private SocketUtils() { } 30 | 31 | internal static byte[] getInfo(IPEndPoint ipe, Packet packet) 32 | { 33 | //Create the socket 34 | Socket srvSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 35 | 36 | //Save the max packet size 37 | int packetSize = 12288; 38 | 39 | //Send/Receive timeouts 40 | srvSocket.SendTimeout = 3000; 41 | srvSocket.ReceiveTimeout = 3000; 42 | 43 | try 44 | { 45 | //Send the request to the server 46 | srvSocket.SendTo(packet.outputAsBytes(), ipe); 47 | } 48 | catch (SocketException se) 49 | { 50 | throw new SSQLServerException("Could not send packet to server {" + se.Message + "}"); 51 | } 52 | 53 | //Create a new receive buffer 54 | byte[] rcvPacketInfo = new byte[packetSize]; 55 | EndPoint Remote = (EndPoint)ipe; 56 | 57 | try 58 | { 59 | //Receive the data from the server 60 | srvSocket.ReceiveFrom(rcvPacketInfo, ref Remote); 61 | } 62 | catch (SocketException se) 63 | { 64 | throw new SSQLServerException("Could not receive packet from server {" + se.Message + "}"); 65 | } 66 | 67 | //Send the information back 68 | return rcvPacketInfo; 69 | } 70 | 71 | internal static byte[] getInfo(IPEndPoint ipe, byte[] request) 72 | { 73 | //Create the socket 74 | Socket srvSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 75 | 76 | //Save the max packet size 77 | int packetSize = 12288; 78 | 79 | //Send/Receive timeouts 80 | srvSocket.SendTimeout = 3000; 81 | srvSocket.ReceiveTimeout = 3000; 82 | 83 | try 84 | { 85 | //Send the request to the server 86 | srvSocket.SendTo(request, ipe); 87 | } 88 | catch (SocketException se) 89 | { 90 | throw new SSQLServerException("Could not send packet to server {" + se.Message + "}"); 91 | } 92 | 93 | //Create a new receive buffer 94 | byte[] rcvPacketInfo = new byte[packetSize]; 95 | EndPoint Remote = (EndPoint)ipe; 96 | 97 | try 98 | { 99 | //Receive the data from the server 100 | srvSocket.ReceiveFrom(rcvPacketInfo, ref Remote); 101 | } 102 | catch (SocketException se) 103 | { 104 | throw new SSQLServerException("Could not receive packet from server {" + se.Message + "}"); 105 | } 106 | 107 | //Send the information back 108 | return rcvPacketInfo; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /ArkData/Tribe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ArkData 5 | { 6 | public class Tribe 7 | { 8 | public int Id { get; set; } 9 | public string Name { get; set; } 10 | public DateTime FileCreated { get; set; } 11 | public DateTime FileUpdated { get; set; } 12 | public int? OwnerId { get; set; } 13 | public virtual ICollection Players { get; set; } 14 | public virtual Player Owner { get; set; } 15 | 16 | public Tribe() 17 | { 18 | this.Players = (ICollection)new HashSet(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ArkData/TribeParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace ArkData 7 | { 8 | internal partial class Parser 9 | { 10 | private static uint GetOwnerId(byte[] data) 11 | { 12 | byte[] bytes1 = Encoding.Default.GetBytes("OwnerPlayerDataID"); 13 | byte[] bytes2 = Encoding.Default.GetBytes("UInt32Property"); 14 | int offset = data.LocateFirst(bytes1, 0); 15 | int num = data.LocateFirst(bytes2, offset); 16 | return BitConverter.ToUInt32(data, num + bytes2.Length + 9); 17 | } 18 | 19 | public static Tribe ParseTribe(string fileName) 20 | { 21 | FileInfo fileInfo = new FileInfo(fileName); 22 | if (!fileInfo.Exists) 23 | return null; 24 | 25 | byte[] data = File.ReadAllBytes(fileName); 26 | 27 | return new Tribe() 28 | { 29 | Id = Helpers.GetInt(data, "TribeID"), 30 | Name = Helpers.GetString(data, "TribeName"), 31 | OwnerId = (int?)GetOwnerId(data), 32 | 33 | FileCreated = fileInfo.CreationTime, 34 | FileUpdated = fileInfo.LastWriteTime 35 | }; 36 | } 37 | 38 | public static Task ParseTribeAsync(string fileName) 39 | { 40 | return Task.Run(() => 41 | { 42 | return ParseTribe(fileName); 43 | }); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ArkData/obj/Debug/ArkData.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\ArkData.dll 2 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\ArkData.pdb 3 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\Newtonsoft.Json.dll 4 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\SSQLib.dll 5 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\Newtonsoft.Json.xml 6 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\obj\Debug\ArkData.csprojResolveAssemblyReference.cache 7 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\obj\Debug\ArkData.dll 8 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\obj\Debug\ArkData.pdb 9 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\SSQLib.pdb 10 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Debug\SSQLib.xml 11 | C:\Users\Admin\Documents\Git\ArkData\ArkData\bin\Debug\ArkData.dll 12 | C:\Users\Admin\Documents\Git\ArkData\ArkData\bin\Debug\ArkData.pdb 13 | C:\Users\Admin\Documents\Git\ArkData\ArkData\bin\Debug\Newtonsoft.Json.dll 14 | C:\Users\Admin\Documents\Git\ArkData\ArkData\bin\Debug\Newtonsoft.Json.xml 15 | C:\Users\Admin\Documents\Git\ArkData\ArkData\obj\Debug\ArkData.csprojResolveAssemblyReference.cache 16 | C:\Users\Admin\Documents\Git\ArkData\ArkData\obj\Debug\ArkData.dll 17 | C:\Users\Admin\Documents\Git\ArkData\ArkData\obj\Debug\ArkData.pdb 18 | -------------------------------------------------------------------------------- /ArkData/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/ArkData/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -------------------------------------------------------------------------------- /ArkData/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/ArkData/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -------------------------------------------------------------------------------- /ArkData/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/ArkData/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -------------------------------------------------------------------------------- /ArkData/obj/Release/ArkData.csproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Release\ArkData.dll 2 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Release\ArkData.pdb 3 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Release\Newtonsoft.Json.dll 4 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Release\SSQLib.dll 5 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\bin\Release\Newtonsoft.Json.xml 6 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\obj\Release\ArkData.dll 7 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\obj\Release\ArkData.pdb 8 | C:\Users\Admin\Documents\Git\Spotty\ArkData\ArkData\obj\Release\ArkData.csprojResolveAssemblyReference.cache 9 | C:\Users\Admin\Documents\Git\ArkData\ArkData\bin\Release\Newtonsoft.Json.dll 10 | C:\Users\Admin\Documents\Git\ArkData\ArkData\bin\Release\Newtonsoft.Json.xml 11 | C:\Users\Admin\Documents\Git\ArkData\ArkData\obj\Release\ArkData.csprojResolveAssemblyReference.cache 12 | C:\Users\Admin\Documents\Git\ArkData\ArkData\obj\Release\ArkData.dll 13 | C:\Users\Admin\Documents\Git\ArkData\ArkData\obj\Release\ArkData.pdb 14 | C:\Users\Admin\documents\Git\ArkData\ArkData\bin\Release\ArkData.dll 15 | C:\Users\Admin\documents\Git\ArkData\ArkData\bin\Release\ArkData.pdb 16 | -------------------------------------------------------------------------------- /ArkData/obj/Release/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/ArkData/obj/Release/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -------------------------------------------------------------------------------- /ArkData/obj/Release/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/ArkData/obj/Release/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -------------------------------------------------------------------------------- /ArkData/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/ArkData/obj/Release/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -------------------------------------------------------------------------------- /ArkData/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #![Logo](https://web.mxcontent.network/ark-data/arkdata.png) ARK Server Data Reader# 2 | 3 | The core mechanics are based on Player & Tribe Viewer made by [xU] .$pIrit 4 | we wanted to make the mechanics more easily implementable into other components. 5 | 6 |

NOTE: This implementation is deprecated and most likely won't work with your version of the server.

7 | 8 |

How to use it

9 | 10 | ArkData is very easy to use: 11 | 12 | ```C# 13 | var container = ArkData.ArkDataContainer.Create("Saved data directory"); 14 | 15 | txtName.text = container.Players[0].CharacterName; 16 | txtLevel.text = container.Players[0].Level; 17 | ``` 18 | 19 | If you want to use the extended information such as the steam profile data you'll have to load the steam information for the players. 20 | To use the Steam functionalities you need to have an access key to use with the Steam API. You can create one here. 21 | Steam data can be loaded like this: 22 | 23 | ```C# 24 | container.LoadSteam("API Key"); 25 | 26 | txtSteamName.text = container.Players[0].SteamName; 27 | txtProfileURL.text = container.Players[0].ProfileUrl; 28 | ``` 29 | 30 | Last but not least we have the functionality to check who of the players is online. To use this function you need to have loaded the users Steam data. This is necessary to bind the online users to their server profiles. 31 | 32 | ```C# 33 | container.LoadOnlinePlayers("127.0.0.1", 27015); 34 | 35 | txtOnline.text = container.Players[0].Online; 36 | ``` 37 | 38 |

Using the async pattern

39 | 40 | All the mechanics work precisely the same but have been added into an async pattern. 41 | 42 | ```C# 43 | var container = await ArkData.ArkDataContainer.CreateAsync("Saved data directory"); 44 | 45 | txtName.text = container.Players[0].CharacterName; 46 | txtLevel.text = container.Players[0].Level; 47 | 48 | await container.LoadSteamAsync("API Key"); 49 | 50 | txtSteamName.text = container.Players[0].SteamName; 51 | txtProfileURL.text = container.Players[0].ProfileUrl; 52 | 53 | await container.LoadOnlinePlayersAsync("127.0.0.1", 27015); 54 | 55 | txtOnline.text = container.Players[0].Online; 56 | ``` 57 |

Cross-platform compatibility

58 | 59 | The sources of all the dependencies are available and no unsupported features are used in the development of ArkData it can be compiled with Mono. You might have to change a line or two to compensate for environmental differences. The core mechanics should work under Linux and Mac OS X, although this is untested. 60 | 61 |

Third-party Sources

62 | 63 | - NewtonSoft.Json 64 | - SSQ Lib 65 | -------------------------------------------------------------------------------- /packages/Newtonsoft.Json.7.0.1/Newtonsoft.Json.7.0.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AuthiQ/ArkData/eb9b0513c2bb6c73a531c5ff79ef5d832afe560b/packages/Newtonsoft.Json.7.0.1/Newtonsoft.Json.7.0.1.nupkg -------------------------------------------------------------------------------- /packages/Newtonsoft.Json.7.0.1/[Content_Types].xml: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /packages/Newtonsoft.Json.7.0.1/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | # open json.net splash page on package install 4 | # don't open if json.net is installed as a dependency 5 | 6 | try 7 | { 8 | $url = "http://www.newtonsoft.com/json/install?version=" + $package.Version 9 | $dte2 = Get-Interface $dte ([EnvDTE80.DTE2]) 10 | 11 | if ($dte2.ActiveWindow.Caption -eq "Package Manager Console") 12 | { 13 | # user is installing from VS NuGet console 14 | # get reference to the window, the console host and the input history 15 | # show webpage if "install-package newtonsoft.json" was last input 16 | 17 | $consoleWindow = $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow]) 18 | 19 | $props = $consoleWindow.GetType().GetProperties([System.Reflection.BindingFlags]::Instance -bor ` 20 | [System.Reflection.BindingFlags]::NonPublic) 21 | 22 | $prop = $props | ? { $_.Name -eq "ActiveHostInfo" } | select -first 1 23 | if ($prop -eq $null) { return } 24 | 25 | $hostInfo = $prop.GetValue($consoleWindow) 26 | if ($hostInfo -eq $null) { return } 27 | 28 | $history = $hostInfo.WpfConsole.InputHistory.History 29 | 30 | $lastCommand = $history | select -last 1 31 | 32 | if ($lastCommand) 33 | { 34 | $lastCommand = $lastCommand.Trim().ToLower() 35 | if ($lastCommand.StartsWith("install-package") -and $lastCommand.Contains("newtonsoft.json")) 36 | { 37 | $dte2.ItemOperations.Navigate($url) | Out-Null 38 | } 39 | } 40 | } 41 | else 42 | { 43 | # user is installing from VS NuGet dialog 44 | # get reference to the window, then smart output console provider 45 | # show webpage if messages in buffered console contains "installing...newtonsoft.json" in last operation 46 | 47 | $instanceField = [NuGet.Dialog.PackageManagerWindow].GetField("CurrentInstance", [System.Reflection.BindingFlags]::Static -bor ` 48 | [System.Reflection.BindingFlags]::NonPublic) 49 | 50 | $consoleField = [NuGet.Dialog.PackageManagerWindow].GetField("_smartOutputConsoleProvider", [System.Reflection.BindingFlags]::Instance -bor ` 51 | [System.Reflection.BindingFlags]::NonPublic) 52 | 53 | if ($instanceField -eq $null -or $consoleField -eq $null) { return } 54 | 55 | $instance = $instanceField.GetValue($null) 56 | 57 | if ($instance -eq $null) { return } 58 | 59 | $consoleProvider = $consoleField.GetValue($instance) 60 | if ($consoleProvider -eq $null) { return } 61 | 62 | $console = $consoleProvider.CreateOutputConsole($false) 63 | 64 | $messagesField = $console.GetType().GetField("_messages", [System.Reflection.BindingFlags]::Instance -bor ` 65 | [System.Reflection.BindingFlags]::NonPublic) 66 | if ($messagesField -eq $null) { return } 67 | 68 | $messages = $messagesField.GetValue($console) 69 | if ($messages -eq $null) { return } 70 | 71 | $operations = $messages -split "==============================" 72 | 73 | $lastOperation = $operations | select -last 1 74 | 75 | if ($lastOperation) 76 | { 77 | $lastOperation = $lastOperation.ToLower() 78 | 79 | $lines = $lastOperation -split "`r`n" 80 | 81 | $installMatch = $lines | ? { $_.StartsWith("------- installing...newtonsoft.json ") } | select -first 1 82 | 83 | if ($installMatch) 84 | { 85 | $dte2.ItemOperations.Navigate($url) | Out-Null 86 | } 87 | } 88 | } 89 | } 90 | catch 91 | { 92 | try 93 | { 94 | $pmPane = $dte2.ToolWindows.OutputWindow.OutputWindowPanes.Item("Package Manager") 95 | 96 | $selection = $pmPane.TextDocument.Selection 97 | $selection.StartOfDocument($false) 98 | $selection.EndOfDocument($true) 99 | 100 | if ($selection.Text.StartsWith("Attempting to gather dependencies information for package 'Newtonsoft.Json." + $package.Version + "'")) 101 | { 102 | $dte2.ItemOperations.Navigate($url) | Out-Null 103 | } 104 | } 105 | catch 106 | { 107 | # stop potential errors from bubbling up 108 | # worst case the splash page won't open 109 | } 110 | } 111 | 112 | # still yolo --------------------------------------------------------------------------------