├── .gitignore ├── BattleNET client ├── BattleNET client.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── app.config ├── BattleNET.sln ├── BattleNET ├── BattlEyeClient.cs ├── BattlEyeCommand.cs ├── BattlEyeCommandResult.cs ├── BattlEyeConnectionResult.cs ├── BattlEyeDisconnectEventArgs.cs ├── BattlEyeDisconnectionType.cs ├── BattlEyeMessageEventArgs.cs ├── BattlEyePacketType.cs ├── BattleEyeLoginCredentials.cs ├── BattleNET.csproj ├── BattleNET.nuspec ├── CRC32.cs └── Helpers.cs ├── README.md ├── authors.txt ├── changelog.txt └── license.txt /.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 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.dbproj.schemaview 158 | *.pfx 159 | *.publishsettings 160 | node_modules/ 161 | 162 | # RIA/Silverlight projects 163 | Generated_Code/ 164 | 165 | # Backup & report files from converting an old project file 166 | # to a newer Visual Studio version. Backup files are not needed, 167 | # because we have git ;-) 168 | _UpgradeReport_Files/ 169 | Backup*/ 170 | UpgradeLog*.XML 171 | UpgradeLog*.htm 172 | 173 | # SQL Server files 174 | *.mdf 175 | *.ldf 176 | 177 | # Business Intelligence projects 178 | *.rdl.data 179 | *.bim.layout 180 | *.bim_*.settings 181 | 182 | # Microsoft Fakes 183 | FakesAssemblies/ 184 | src/.vs/ 185 | *.orig 186 | .vs/ 187 | -------------------------------------------------------------------------------- /BattleNET client/BattleNET client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {F6671269-E70E-4502-A7F5-7B2AD6955900} 9 | Exe 10 | Properties 11 | BattleNET_client 12 | BattleNET client 13 | v4.6.1 14 | 15 | 16 | 512 17 | publish\ 18 | true 19 | Disk 20 | false 21 | Foreground 22 | 7 23 | Days 24 | false 25 | false 26 | true 27 | 0 28 | 1.0.0.%2a 29 | false 30 | false 31 | true 32 | 33 | 34 | x86 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | false 43 | 44 | 45 | x86 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | false 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900} 70 | BattleNET 71 | 72 | 73 | 74 | 75 | False 76 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 77 | true 78 | 79 | 80 | False 81 | .NET Framework 3.5 SP1 Client Profile 82 | false 83 | 84 | 85 | False 86 | .NET Framework 3.5 SP1 87 | false 88 | 89 | 90 | False 91 | Windows Installer 3.1 92 | true 93 | 94 | 95 | 96 | 97 | 98 | 99 | 106 | -------------------------------------------------------------------------------- /BattleNET client/Program.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | using System.Net; 10 | using System.Text; 11 | using BattleNET; 12 | 13 | namespace BattleNET_client 14 | { 15 | internal class Program 16 | { 17 | private static void Main(string[] args) 18 | { 19 | Console.WriteLine( 20 | "BattleNET v1.3.4 - BattlEye Library and Client\n\n" + 21 | "Copyright (C) 2018 by it's authors.\n" + 22 | "Some rights reserved. See license.txt, authors.txt.\n" 23 | ); 24 | 25 | BattlEyeLoginCredentials loginCredentials; 26 | string command = ""; 27 | 28 | Console.OutputEncoding = Encoding.UTF8; 29 | 30 | if (args.Length > 0) 31 | { 32 | loginCredentials = GetLoginCredentials(args); 33 | 34 | for (int i = 0; i < args.Length; i++) 35 | { 36 | if (args[i] == "-command") 37 | { 38 | try 39 | { 40 | command = args[i + 1]; 41 | } 42 | catch 43 | { 44 | Console.WriteLine("No command given!"); 45 | loginCredentials.Host = null; 46 | } 47 | } 48 | } 49 | 50 | if (loginCredentials.Host == null || loginCredentials.Port == 0 || loginCredentials.Password == "") 51 | { 52 | Console.WriteLine("BattleNET client usage:"); 53 | Console.WriteLine("BattleNET client.exe -host 127.0.0.1 -port 2302 -password admin [-command shutdown]"); 54 | Console.Read(); 55 | Environment.Exit(0); 56 | } 57 | } 58 | else 59 | { 60 | loginCredentials = GetLoginCredentials(); 61 | } 62 | 63 | Console.Title = string.Format("BattleNET client v1.3.4 - {0}:{1}", loginCredentials.Host, loginCredentials.Port); 64 | 65 | BattlEyeClient b = new BattlEyeClient(loginCredentials); 66 | b.BattlEyeMessageReceived += BattlEyeMessageReceived; 67 | b.BattlEyeConnected += BattlEyeConnected; 68 | b.BattlEyeDisconnected += BattlEyeDisconnected; 69 | b.ReconnectOnPacketLoss = true; 70 | b.Connect(); 71 | 72 | if (command != "") 73 | { 74 | b.SendCommand(command); 75 | while (b.CommandQueue > 0) { /* wait until server received packet */ }; 76 | } 77 | else 78 | { 79 | while (true) 80 | { 81 | string cmd = Console.ReadLine(); 82 | 83 | if (cmd == "exit" || cmd == "logout") 84 | { 85 | break; 86 | } 87 | 88 | if (b.Connected) 89 | { 90 | b.SendCommand(cmd); 91 | } 92 | else 93 | { 94 | Environment.Exit(0); 95 | } 96 | } 97 | } 98 | 99 | b.Disconnect(); 100 | } 101 | 102 | private static void BattlEyeConnected(BattlEyeConnectEventArgs args) 103 | { 104 | //if (args.ConnectionResult == BattlEyeConnectionResult.Success) { /* Connected successfully */ } 105 | //if (args.ConnectionResult == BattlEyeConnectionResult.InvalidLogin) { /* Connection failed, invalid login details */ } 106 | //if (args.ConnectionResult == BattlEyeConnectionResult.ConnectionFailed) { /* Connection failed, host unreachable */ } 107 | 108 | Console.WriteLine(args.Message); 109 | } 110 | 111 | private static void BattlEyeDisconnected(BattlEyeDisconnectEventArgs args) 112 | { 113 | //if (args.DisconnectionType == BattlEyeDisconnectionType.ConnectionLost) { /* Connection lost (timeout), if ReconnectOnPacketLoss is set to true it will reconnect */ } 114 | //if (args.DisconnectionType == BattlEyeDisconnectionType.SocketException) { /* Something went terribly wrong... */ } 115 | //if (args.DisconnectionType == BattlEyeDisconnectionType.Manual) { /* Disconnected by implementing application, that would be you */ } 116 | 117 | Console.WriteLine(args.Message); 118 | } 119 | 120 | private static void BattlEyeMessageReceived(BattlEyeMessageEventArgs args) 121 | { 122 | //if (args.Id == playerListId) 123 | //{ 124 | // playerList = args.Message; 125 | //} 126 | 127 | Console.WriteLine(args.Message); 128 | } 129 | 130 | private static BattlEyeLoginCredentials GetLoginCredentials(string[] args) 131 | { 132 | BattlEyeLoginCredentials loginCredentials = new BattlEyeLoginCredentials(); 133 | loginCredentials.Host = null; 134 | loginCredentials.Port = 0; 135 | loginCredentials.Password = ""; 136 | 137 | for (int i = 0; i < args.Length; i = i + 2) 138 | { 139 | switch (args[i]) 140 | { 141 | case "-host": 142 | { 143 | try 144 | { 145 | IPAddress ip = Dns.GetHostAddresses(args[i + 1])[0]; 146 | loginCredentials.Host = ip; 147 | } 148 | catch 149 | { 150 | Console.WriteLine("No valid host given!"); 151 | } 152 | break; 153 | } 154 | 155 | case "-port": 156 | { 157 | int value; 158 | if (int.TryParse(args[i + 1], out value)) 159 | { 160 | loginCredentials.Port = value; 161 | } 162 | else 163 | { 164 | Console.WriteLine("No valid port given!"); 165 | } 166 | break; 167 | } 168 | 169 | case "-password": 170 | { 171 | if (args[i + 1] != "") 172 | { 173 | loginCredentials.Password = args[i + 1]; 174 | } 175 | else 176 | { 177 | Console.WriteLine("No password given!"); 178 | } 179 | break; 180 | } 181 | } 182 | } 183 | 184 | return loginCredentials; 185 | } 186 | 187 | private static BattlEyeLoginCredentials GetLoginCredentials() 188 | { 189 | IPAddress host = null; 190 | int port = 0; 191 | string password = ""; 192 | 193 | do 194 | { 195 | string input; 196 | Console.Write("Enter IP address or hostname: "); 197 | input = Console.ReadLine(); 198 | 199 | try 200 | { 201 | IPAddress ip = Dns.GetHostAddresses(input)[0]; 202 | host = ip; 203 | } 204 | catch { /* try again */ } 205 | } while (host == null); 206 | 207 | do 208 | { 209 | int value; 210 | string input; 211 | Console.Write("Enter port number: "); 212 | input = Console.ReadLine(); 213 | 214 | if (int.TryParse(input, out value)) 215 | { 216 | port = value; 217 | } 218 | } while (port == 0); 219 | 220 | do 221 | { 222 | Console.Write("Enter RCon password: "); 223 | string input = Console.ReadLine(); 224 | 225 | if (input != "") 226 | { 227 | password = input; 228 | } 229 | } while (password == ""); 230 | 231 | var loginCredentials = new BattlEyeLoginCredentials 232 | { 233 | Host = host, 234 | Port = port, 235 | Password = password, 236 | }; 237 | 238 | return loginCredentials; 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /BattleNET client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | #endregion 7 | 8 | // General Information about an assembly is controlled through the following 9 | // set of attributes. Change these attribute values to modify the information 10 | // associated with an assembly. 11 | 12 | [assembly: AssemblyTitle("BattleNET client")] 13 | [assembly: AssemblyDescription("BattlEye Client")] 14 | [assembly: AssemblyConfiguration("")] 15 | [assembly: AssemblyCompany("Marcel de Vries")] 16 | [assembly: AssemblyProduct("BattleNET client")] 17 | [assembly: AssemblyCopyright("Copyright © 2018")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | 29 | [assembly: Guid("57d2997b-d6f2-4f8e-b9b0-c89487bdded4")] 30 | 31 | // Version information for an assembly consists of the following four values: 32 | // 33 | // Major Version 34 | // Minor Version 35 | // Build Number 36 | // Revision 37 | // 38 | // You can specify all the values or you can default the Build and Revision Numbers 39 | // by using the '*' as shown below: 40 | // [assembly: AssemblyVersion("1.0.*")] 41 | 42 | [assembly: AssemblyVersion("1.3.4")] 43 | [assembly: AssemblyFileVersion("1.3.4")] -------------------------------------------------------------------------------- /BattleNET client/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /BattleNET.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BattleNET", "BattleNET\BattleNET.csproj", "{4FBB3734-215B-45B1-BDBC-0EFA156A6900}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BattleNET client", "BattleNET client\BattleNET client.csproj", "{F6671269-E70E-4502-A7F5-7B2AD6955900}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|Mixed Platforms = Debug|Mixed Platforms 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|Mixed Platforms = Release|Mixed Platforms 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 21 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 22 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Debug|x86.ActiveCfg = Debug|Any CPU 23 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 26 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Release|Mixed Platforms.Build.0 = Release|Any CPU 27 | {4FBB3734-215B-45B1-BDBC-0EFA156A6900}.Release|x86.ActiveCfg = Release|Any CPU 28 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Debug|Any CPU.ActiveCfg = Debug|x86 29 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 30 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Debug|Mixed Platforms.Build.0 = Debug|x86 31 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Debug|x86.ActiveCfg = Debug|x86 32 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Debug|x86.Build.0 = Debug|x86 33 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Release|Any CPU.ActiveCfg = Release|x86 34 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Release|Mixed Platforms.ActiveCfg = Release|x86 35 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Release|Mixed Platforms.Build.0 = Release|x86 36 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Release|x86.ActiveCfg = Release|x86 37 | {F6671269-E70E-4502-A7F5-7B2AD6955900}.Release|x86.Build.0 = Release|x86 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /BattleNET/BattlEyeClient.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Globalization; 11 | using System.Linq; 12 | using System.Net; 13 | using System.Net.Sockets; 14 | using System.Text; 15 | using System.Threading.Tasks; 16 | 17 | namespace BattleNET 18 | { 19 | public class BattlEyeClient 20 | { 21 | private Socket _socket; 22 | private DateTime _packetSent; 23 | private DateTime _packetReceived; 24 | private BattlEyeDisconnectionType? _disconnectionType; 25 | private bool _keepRunning; 26 | private int _sequenceNumber; 27 | private int _currentPacket; 28 | private SortedDictionary _packetQueue; 29 | private BattlEyeLoginCredentials _loginCredentials; 30 | 31 | public bool Connected => _socket != null && _socket.Connected; 32 | 33 | public bool ReconnectOnPacketLoss 34 | { 35 | get; 36 | set; 37 | } 38 | 39 | public int CommandQueue => _packetQueue.Count; 40 | 41 | public BattlEyeClient(BattlEyeLoginCredentials loginCredentials) 42 | { 43 | _loginCredentials = loginCredentials; 44 | } 45 | 46 | public BattlEyeConnectionResult Connect() 47 | { 48 | return ConnectInternal(100); 49 | } 50 | 51 | private BattlEyeConnectionResult ConnectInternal(int counter) 52 | { 53 | _packetSent = DateTime.Now; 54 | _packetReceived = DateTime.Now; 55 | 56 | _sequenceNumber = 0; 57 | _currentPacket = -1; 58 | _packetQueue = new SortedDictionary(); 59 | _keepRunning = true; 60 | 61 | var remoteEp = new IPEndPoint(_loginCredentials.Host, _loginCredentials.Port); 62 | _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) 63 | { 64 | ReceiveBufferSize = int.MaxValue, 65 | ReceiveTimeout = 5000 66 | }; 67 | 68 | try 69 | { 70 | _socket.Connect(remoteEp); 71 | 72 | if (SendLoginPacket(_loginCredentials.Password) == BattlEyeCommandResult.Error) 73 | return BattlEyeConnectionResult.ConnectionFailed; 74 | 75 | var bytesReceived = new Byte[4096]; 76 | 77 | _socket.Receive(bytesReceived, bytesReceived.Length, 0); 78 | 79 | if (bytesReceived[7] == 0x00) 80 | { 81 | if (bytesReceived[8] == 0x01) 82 | { 83 | OnConnect(_loginCredentials, BattlEyeConnectionResult.Success); 84 | 85 | Receive(); 86 | } 87 | else 88 | { 89 | OnConnect(_loginCredentials, BattlEyeConnectionResult.InvalidLogin); 90 | return BattlEyeConnectionResult.InvalidLogin; 91 | } 92 | } 93 | } 94 | catch 95 | { 96 | if (_disconnectionType == BattlEyeDisconnectionType.ConnectionLost) 97 | { 98 | Disconnect(BattlEyeDisconnectionType.ConnectionLost); 99 | 100 | if (counter > 0) 101 | { 102 | return ConnectInternal(counter - 1); 103 | } 104 | 105 | return BattlEyeConnectionResult.ConnectionFailed; 106 | } 107 | else 108 | { 109 | OnConnect(_loginCredentials, BattlEyeConnectionResult.ConnectionFailed); 110 | return BattlEyeConnectionResult.ConnectionFailed; 111 | } 112 | } 113 | 114 | return BattlEyeConnectionResult.Success; 115 | } 116 | 117 | private BattlEyeCommandResult SendLoginPacket(string command) 118 | { 119 | try 120 | { 121 | if (!_socket.Connected) 122 | return BattlEyeCommandResult.NotConnected; 123 | 124 | byte[] packet = ConstructPacket(BattlEyePacketType.Login, 0, command); 125 | _socket.Send(packet); 126 | 127 | _packetSent = DateTime.Now; 128 | } 129 | catch 130 | { 131 | return BattlEyeCommandResult.Error; 132 | } 133 | 134 | return BattlEyeCommandResult.Success; 135 | } 136 | 137 | private BattlEyeCommandResult SendAcknowledgePacket(string command) 138 | { 139 | try 140 | { 141 | if (!_socket.Connected) return BattlEyeCommandResult.NotConnected; 142 | 143 | byte[] packet = ConstructPacket(BattlEyePacketType.Acknowledge, 0, command); 144 | _socket.Send(packet); 145 | 146 | _packetSent = DateTime.Now; 147 | } 148 | catch 149 | { 150 | return BattlEyeCommandResult.Error; 151 | } 152 | 153 | return BattlEyeCommandResult.Success; 154 | } 155 | 156 | public int SendCommand(string command, bool log = true) 157 | { 158 | return SendCommandPacket(command, log); 159 | } 160 | 161 | private int SendCommandPacket(string command, bool log = true) 162 | { 163 | int packetID = _sequenceNumber; 164 | _sequenceNumber = (_sequenceNumber == 255) ? 0 : _sequenceNumber + 1; 165 | 166 | try 167 | { 168 | if (!_socket.Connected) 169 | return 256; 170 | 171 | var packet = ConstructPacket(BattlEyePacketType.Command, packetID, command); 172 | 173 | _packetSent = DateTime.Now; 174 | 175 | if (log) 176 | { 177 | _packetQueue.Add(packetID, new[] { command, _packetSent.ToString(CultureInfo.InvariantCulture) }); 178 | } 179 | else 180 | { 181 | SendPacket(packet); 182 | } 183 | } 184 | catch 185 | { 186 | return 256; 187 | } 188 | 189 | return packetID; 190 | } 191 | 192 | public int SendCommand(BattlEyeCommand command, string parameters = "") 193 | { 194 | return SendCommandPacket(command, parameters); 195 | } 196 | 197 | private int SendCommandPacket(BattlEyeCommand command, string parameters = "") 198 | { 199 | int packetID = _sequenceNumber; 200 | _sequenceNumber = (_sequenceNumber == 255) ? 0 : _sequenceNumber + 1; 201 | 202 | try 203 | { 204 | if (!_socket.Connected) 205 | return 256; 206 | 207 | ConstructPacket(BattlEyePacketType.Command, packetID, Helpers.StringValueOf(command) + parameters); 208 | 209 | _packetSent = DateTime.Now; 210 | 211 | _packetQueue.Add(packetID, new[] { Helpers.StringValueOf(command) + parameters, _packetSent.ToString(CultureInfo.InvariantCulture) }); 212 | } 213 | catch 214 | { 215 | return 256; 216 | } 217 | 218 | return packetID; 219 | } 220 | 221 | private void SendPacket(byte[] packet) 222 | { 223 | _socket.Send(packet); 224 | } 225 | 226 | private byte[] ConstructPacket(BattlEyePacketType packetType, int sequenceNumber, string command) 227 | { 228 | string type; 229 | 230 | switch (packetType) 231 | { 232 | case BattlEyePacketType.Login: 233 | type = Helpers.Hex2Ascii("FF00"); 234 | break; 235 | case BattlEyePacketType.Command: 236 | type = Helpers.Hex2Ascii("FF01"); 237 | break; 238 | case BattlEyePacketType.Acknowledge: 239 | type = Helpers.Hex2Ascii("FF02"); 240 | break; 241 | default: 242 | return new byte[] { }; 243 | } 244 | 245 | if (packetType != BattlEyePacketType.Acknowledge) 246 | { 247 | if (command != null) command = Encoding.GetEncoding(1252).GetString(Encoding.UTF8.GetBytes(command)); 248 | } 249 | 250 | var count = Helpers.Bytes2String(new[] { (byte)sequenceNumber }); 251 | 252 | var byteArray = new CRC32().ComputeHash(Helpers.String2Bytes(type + ((packetType != BattlEyePacketType.Command) ? "" : count) + command)); 253 | 254 | var hash = new string(Helpers.Hex2Ascii(BitConverter.ToString(byteArray).Replace("-", "")).ToCharArray().Reverse().ToArray()); 255 | 256 | var packet = "BE" + hash + type + ((packetType != BattlEyePacketType.Command) ? "" : count) + command; 257 | 258 | return Helpers.String2Bytes(packet); 259 | } 260 | 261 | public void Disconnect() 262 | { 263 | _keepRunning = false; 264 | 265 | if (_socket.Connected) 266 | { 267 | _socket.Shutdown(SocketShutdown.Both); 268 | _socket.Close(); 269 | } 270 | 271 | OnDisconnect(_loginCredentials, BattlEyeDisconnectionType.Manual); 272 | } 273 | 274 | private void Disconnect(BattlEyeDisconnectionType? disconnectionType) 275 | { 276 | if (disconnectionType == BattlEyeDisconnectionType.ConnectionLost) 277 | _disconnectionType = BattlEyeDisconnectionType.ConnectionLost; 278 | 279 | _keepRunning = false; 280 | 281 | if (_socket.Connected) 282 | { 283 | _socket.Shutdown(SocketShutdown.Both); 284 | _socket.Close(); 285 | } 286 | 287 | if (disconnectionType != null) 288 | OnDisconnect(_loginCredentials, disconnectionType); 289 | } 290 | 291 | private async void Receive() 292 | { 293 | var state = new StateObject { WorkSocket = _socket }; 294 | 295 | _disconnectionType = null; 296 | 297 | _socket.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, ReceiveCallback, state); 298 | 299 | while (_socket.Connected && _keepRunning) 300 | { 301 | int timeoutClient = (int)(DateTime.Now - _packetSent).TotalSeconds; 302 | int timeoutServer = (int)(DateTime.Now - _packetReceived).TotalSeconds; 303 | 304 | if (timeoutClient >= 5) 305 | { 306 | if (timeoutServer >= 20) 307 | { 308 | Disconnect(BattlEyeDisconnectionType.ConnectionLost); 309 | _keepRunning = true; 310 | } 311 | else 312 | { 313 | if (_packetQueue.Count == 0) 314 | { 315 | SendCommandPacket(null, false); 316 | } 317 | } 318 | } 319 | 320 | if (_socket.Connected && _packetQueue.Count > 0 && _socket.Available == 0) 321 | { 322 | try 323 | { 324 | int key = _packetQueue.First().Key; 325 | 326 | if (_currentPacket == -1 || !_packetQueue.ContainsKey(_currentPacket)) 327 | { 328 | _currentPacket = key; 329 | string value = _packetQueue[key][0]; 330 | SendPacket(ConstructPacket(BattlEyePacketType.Command, key, value)); 331 | } 332 | } 333 | catch 334 | { 335 | // Prevent possible crash when packet is received at the same moment it's trying to resend it. 336 | } 337 | } 338 | 339 | await Task.Delay(250); 340 | } 341 | 342 | if (!_socket.Connected) 343 | { 344 | if (ReconnectOnPacketLoss && _keepRunning) 345 | { 346 | Connect(); 347 | } 348 | else if (!_keepRunning) 349 | { 350 | //let the thread finish without further action 351 | } 352 | else 353 | { 354 | OnDisconnect(_loginCredentials, BattlEyeDisconnectionType.ConnectionLost); 355 | } 356 | } 357 | 358 | } 359 | 360 | private void ReceiveCallback(IAsyncResult ar) 361 | { 362 | try 363 | { 364 | StateObject state = (StateObject)ar.AsyncState; 365 | Socket client = state.WorkSocket; 366 | 367 | // this method can be called from the middle of a .Disconnect() call 368 | // test with Debug > Exception > CLR exs on 369 | if (!client.Connected) 370 | { 371 | return; 372 | } 373 | 374 | int bytesRead = client.EndReceive(ar); 375 | 376 | if (state.Buffer[7] == 0x02) 377 | { 378 | SendAcknowledgePacket(Helpers.Bytes2String(new[] { state.Buffer[8] })); 379 | OnBattlEyeMessage(Helpers.Bytes2String(state.Buffer, 9, bytesRead - 9), 256); 380 | } 381 | else if (state.Buffer[7] == 0x01) 382 | { 383 | if (bytesRead > 9) 384 | { 385 | if (state.Buffer[7] == 0x01 && state.Buffer[9] == 0x00) 386 | { 387 | if (state.Buffer[11] == 0) 388 | { 389 | state.PacketsTodo = state.Buffer[10]; 390 | } 391 | 392 | if (state.PacketsTodo > 0) 393 | { 394 | state.Message.Append(Helpers.Bytes2String(state.Buffer, 12, bytesRead - 12)); 395 | state.PacketsTodo--; 396 | } 397 | 398 | if (state.PacketsTodo == 0) 399 | { 400 | OnBattlEyeMessage(state.Message.ToString(), state.Buffer[8]); 401 | state.Message = new StringBuilder(); 402 | state.PacketsTodo = 0; 403 | } 404 | } 405 | else 406 | { 407 | // Temporary fix to avoid infinite loops with multi-packet server messages 408 | state.Message = new StringBuilder(); 409 | state.PacketsTodo = 0; 410 | 411 | OnBattlEyeMessage(Helpers.Bytes2String(state.Buffer, 9, bytesRead - 9), state.Buffer[8]); 412 | } 413 | } 414 | 415 | if (_packetQueue.ContainsKey(state.Buffer[8]) && state.PacketsTodo == 0) 416 | { 417 | _packetQueue.Remove(state.Buffer[8]); 418 | } 419 | } 420 | 421 | _packetReceived = DateTime.Now; 422 | 423 | client.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, ReceiveCallback, state); 424 | } 425 | catch 426 | { 427 | // do nothing 428 | } 429 | } 430 | 431 | private void OnBattlEyeMessage(string message, int id) 432 | { 433 | BattlEyeMessageReceived?.Invoke(new BattlEyeMessageEventArgs(message, id)); 434 | } 435 | 436 | private void OnConnect(BattlEyeLoginCredentials loginDetails, BattlEyeConnectionResult connectionResult) 437 | { 438 | if (connectionResult == BattlEyeConnectionResult.ConnectionFailed || connectionResult == BattlEyeConnectionResult.InvalidLogin) 439 | Disconnect(null); 440 | 441 | BattlEyeConnected?.Invoke(new BattlEyeConnectEventArgs(loginDetails, connectionResult)); 442 | } 443 | 444 | private void OnDisconnect(BattlEyeLoginCredentials loginDetails, BattlEyeDisconnectionType? disconnectionType) 445 | { 446 | BattlEyeDisconnected?.Invoke(new BattlEyeDisconnectEventArgs(loginDetails, disconnectionType)); 447 | } 448 | 449 | public event BattlEyeMessageEventHandler BattlEyeMessageReceived; 450 | public event BattlEyeConnectEventHandler BattlEyeConnected; 451 | public event BattlEyeDisconnectEventHandler BattlEyeDisconnected; 452 | } 453 | 454 | public class StateObject 455 | { 456 | public Socket WorkSocket; 457 | public const int BufferSize = 2048; 458 | public byte[] Buffer = new byte[BufferSize]; 459 | public StringBuilder Message = new StringBuilder(); 460 | public int PacketsTodo; 461 | } 462 | } 463 | -------------------------------------------------------------------------------- /BattleNET/BattlEyeCommand.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | using System.ComponentModel; 10 | 11 | namespace BattleNET 12 | { 13 | public enum BattlEyeCommand 14 | { 15 | /// 16 | /// #init - Reload server config file loaded by –config option. 17 | /// 18 | [Description("#init")] 19 | Init, 20 | 21 | /// 22 | /// #shutdown - Shuts down the server. 23 | /// 24 | [Description("#shutdown")] 25 | Shutdown, 26 | 27 | /// 28 | /// #reassign - Start over and reassign roles. 29 | /// 30 | [Description("#reassign")] 31 | Reassign, 32 | 33 | /// 34 | /// #restart - Restart mission. 35 | /// 36 | [Description("#restart")] 37 | Restart, 38 | 39 | /// 40 | /// #restartserver - Restart server. 41 | /// 42 | [Description("#restartserver")] 43 | RestartServer, 44 | 45 | /// 46 | /// #lock - Locks the server, prevents new clients from joining. 47 | /// 48 | [Description("#lock")] 49 | Lock, 50 | 51 | /// 52 | /// #unlock - Unlocks the server, allows new clients to join. 53 | /// 54 | [Description("#unlock")] 55 | Unlock, 56 | 57 | /// 58 | /// #mission [missionName] - Loads the given mission on the server. 59 | /// 60 | [Description("#mission ")] 61 | Mission, 62 | 63 | /// 64 | /// missions - Returns a list of the available missions on the server. 65 | /// 66 | [Description("missions")] 67 | Missions, 68 | 69 | /// 70 | /// RConPassword [password] - Changes the RCon password. 71 | /// 72 | [Description("RConPassword ")] 73 | RConPassword, 74 | 75 | /// 76 | /// MaxPing [ping] - Changes the MaxPing value. If a player has a higher ping, he will be kicked from the server. 77 | /// 78 | [Description("MaxPing ")] 79 | MaxPing, 80 | 81 | /// 82 | /// kick [player#] - Kicks a player. His # can be found in the player list using the 'players' command. 83 | /// 84 | [Description("kick ")] 85 | Kick, 86 | 87 | /// 88 | /// players - Displays a list of the players on the server including BE GUIDs and pings. 89 | /// 90 | [Description("players")] 91 | Players, 92 | 93 | /// 94 | /// Say [player#] [msg] - Say something to player #. specially -1 equals all players on server (e.g. 'Say -1 Hello World'). 95 | /// 96 | [Description("Say ")] 97 | Say, 98 | 99 | /// 100 | /// loadBans - (Re)load the BE ban list from bans.txt. 101 | /// 102 | [Description("loadBans")] 103 | LoadBans, 104 | 105 | /// 106 | /// loadScripts - Loads the scripts.txt file without the need to restart server. 107 | /// 108 | [Description("loadScripts")] 109 | LoadScripts, 110 | 111 | /// 112 | /// loadEvents - (Re)load createvehicle.txt, remoteexec.txt and publicvariable.txt 113 | /// 114 | [Description("loadEvents")] 115 | LoadEvents, 116 | 117 | /// 118 | /// loadEvents - (Re)load createvehicle.txt, remoteexec.txt and publicvariable.txt 119 | /// 120 | [Description("loadEvents")] 121 | [Obsolete("This member is obsolette and will be removed in future. Use LoadEvents instead")] 122 | loadEvents, 123 | 124 | /// 125 | /// bans - Show a list of all BE server bans. 126 | /// 127 | [Description("bans")] 128 | Bans, 129 | 130 | /// 131 | /// ban [player #] [time in minutes] [reason] - Ban a player's BE GUID from the server. If time is not specified or 0, the ban will be permanent; if reason is not specified the player will be kicked with "Banned". 132 | /// 133 | [Description("ban ")] 134 | Ban, 135 | 136 | /// 137 | /// addBan [GUID] [time in minutes] [reason] - Same as "ban", but allows to ban a player that is not currently on the server. 138 | /// 139 | [Description("addBan ")] 140 | AddBan, 141 | 142 | /// 143 | /// removeBan [ban #] - Remove ban (get the ban # from the bans command). 144 | /// 145 | [Description("removeBan ")] 146 | RemoveBan, 147 | 148 | /// 149 | /// writeBans - Removes expired bans from bans file. 150 | /// 151 | [Description("writeBans")] 152 | WriteBans, 153 | 154 | /// 155 | /// admins - Gets connected RCON clients. 156 | /// 157 | [Description("admins")] 158 | Admins, 159 | 160 | /// 161 | /// admins - Gets connected RCON clients. 162 | /// 163 | [Description("admins")] 164 | [Obsolete("This member is obsolette and will be removed in future. Use Admins instead")] 165 | admins, 166 | } 167 | } -------------------------------------------------------------------------------- /BattleNET/BattlEyeCommandResult.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | namespace BattleNET 9 | { 10 | public enum BattlEyeCommandResult 11 | { 12 | Success, 13 | Error, 14 | NotConnected, 15 | } 16 | } -------------------------------------------------------------------------------- /BattleNET/BattlEyeConnectionResult.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System.ComponentModel; 9 | 10 | namespace BattleNET 11 | { 12 | public enum BattlEyeConnectionResult 13 | { 14 | [Description("Connected!")] 15 | Success, 16 | 17 | [Description("Host unreachable!")] 18 | ConnectionFailed, 19 | 20 | [Description("Invalid login details!")] 21 | InvalidLogin 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BattleNET/BattlEyeDisconnectEventArgs.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | 10 | namespace BattleNET 11 | { 12 | public delegate void BattlEyeConnectEventHandler(BattlEyeConnectEventArgs args); 13 | public delegate void BattlEyeDisconnectEventHandler(BattlEyeDisconnectEventArgs args); 14 | 15 | public class BattlEyeConnectEventArgs : EventArgs 16 | { 17 | public BattlEyeConnectEventArgs(BattlEyeLoginCredentials loginDetails, BattlEyeConnectionResult connectionResult) 18 | { 19 | LoginDetails = loginDetails; 20 | ConnectionResult = connectionResult; 21 | Message = Helpers.StringValueOf(connectionResult); 22 | } 23 | 24 | public BattlEyeLoginCredentials LoginDetails { get; } 25 | public BattlEyeConnectionResult ConnectionResult { get; } 26 | public string Message { get; } 27 | } 28 | 29 | public class BattlEyeDisconnectEventArgs : EventArgs 30 | { 31 | public BattlEyeDisconnectEventArgs(BattlEyeLoginCredentials loginDetails, BattlEyeDisconnectionType? disconnectionType) 32 | { 33 | LoginDetails = loginDetails; 34 | DisconnectionType = disconnectionType; 35 | Message = Helpers.StringValueOf(disconnectionType); 36 | } 37 | 38 | public BattlEyeLoginCredentials LoginDetails { get; } 39 | public BattlEyeDisconnectionType? DisconnectionType { get; } 40 | public string Message { get; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /BattleNET/BattlEyeDisconnectionType.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System.ComponentModel; 9 | 10 | namespace BattleNET 11 | { 12 | public enum BattlEyeDisconnectionType 13 | { 14 | [Description("Disconnected!")] 15 | Manual, 16 | 17 | [Description("Disconnected! (Connection timeout)")] 18 | ConnectionLost, 19 | 20 | [Description("Disconnected! (Socket Exception)")] 21 | SocketException, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BattleNET/BattlEyeMessageEventArgs.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | 10 | namespace BattleNET 11 | { 12 | public delegate void BattlEyeMessageEventHandler(BattlEyeMessageEventArgs args); 13 | 14 | public class BattlEyeMessageEventArgs : EventArgs 15 | { 16 | public BattlEyeMessageEventArgs(string message, int id) 17 | { 18 | Message = message; 19 | Id = id; 20 | } 21 | 22 | public string Message { get; } 23 | public int Id { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BattleNET/BattlEyePacketType.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | namespace BattleNET 9 | { 10 | enum BattlEyePacketType 11 | { 12 | Login, 13 | Command, 14 | Acknowledge 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BattleNET/BattleEyeLoginCredentials.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System.Net; 9 | 10 | namespace BattleNET 11 | { 12 | public struct BattlEyeLoginCredentials 13 | { 14 | public BattlEyeLoginCredentials(IPAddress host, int port, string password) 15 | : this() 16 | { 17 | Host = host; 18 | Port = port; 19 | Password = password; 20 | } 21 | 22 | public IPAddress Host { get; set; } 23 | public int Port { get; set; } 24 | public string Password { get; set; } 25 | } 26 | } -------------------------------------------------------------------------------- /BattleNET/BattleNET.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 1.3.4 6 | Marcel de Vries 7 | Copyright © 2018 8 | https://github.com/dddlazer/BattleNET/blob/master/license.txt 9 | true 10 | https://github.com/dddlazer/BattleNET 11 | battleye rcon arma server management 12 | 1.3.4.0 13 | 1.3.4.0 14 | https://github.com/dddlazer/BattleNET 15 | git 16 | false 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BattleNET/BattleNET.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | BattleNET 5 | 1.3.4.0 6 | BattleNET 7 | Marcel de Vries 8 | Marcel de Vries 9 | https://github.com/dddlazer/BattleNET/blob/master/license.txt 10 | https://github.com/dddlazer/BattleNET 11 | false 12 | BattlEye Library 13 | Initial NuGet release. 14 | Copyright 2018 15 | battleye rcon arma server management 16 | 17 | 18 | -------------------------------------------------------------------------------- /BattleNET/CRC32.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | using System.Security.Cryptography; 10 | 11 | namespace BattleNET 12 | { 13 | // ReSharper disable once InconsistentNaming 14 | internal class CRC32 : HashAlgorithm 15 | { 16 | public const UInt32 DefaultPolynomial = 0xedb88320; 17 | public const UInt32 DefaultSeed = 0xffffffff; 18 | private static UInt32[] _defaultTable; 19 | 20 | private readonly UInt32 _seed; 21 | private readonly UInt32[] _table; 22 | private UInt32 _hash; 23 | 24 | public CRC32() 25 | { 26 | _table = InitializeTable(DefaultPolynomial); 27 | _seed = DefaultSeed; 28 | Initialize(); 29 | } 30 | 31 | public CRC32(UInt32 polynomial, UInt32 seed) 32 | { 33 | _table = InitializeTable(polynomial); 34 | _seed = seed; 35 | Initialize(); 36 | } 37 | 38 | public override int HashSize 39 | { 40 | get { return 32; } 41 | } 42 | 43 | public override sealed void Initialize() 44 | { 45 | _hash = _seed; 46 | } 47 | 48 | protected override void HashCore(byte[] buffer, int start, int length) 49 | { 50 | _hash = CalculateHash(_table, _hash, buffer, start, length); 51 | } 52 | 53 | protected override byte[] HashFinal() 54 | { 55 | byte[] hashBuffer = UInt32ToBigEndianBytes(~_hash); 56 | HashValue = hashBuffer; 57 | return hashBuffer; 58 | } 59 | 60 | public static UInt32 Compute(byte[] buffer) 61 | { 62 | return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length); 63 | } 64 | 65 | public static UInt32 Compute(UInt32 seed, byte[] buffer) 66 | { 67 | return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length); 68 | } 69 | 70 | public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer) 71 | { 72 | return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); 73 | } 74 | 75 | private static UInt32[] InitializeTable(UInt32 polynomial) 76 | { 77 | if (polynomial == DefaultPolynomial && _defaultTable != null) 78 | return _defaultTable; 79 | 80 | var createTable = new UInt32[256]; 81 | for (int i = 0; i < 256; i++) 82 | { 83 | var entry = (UInt32)i; 84 | for (int j = 0; j < 8; j++) 85 | if ((entry & 1) == 1) 86 | entry = (entry >> 1) ^ polynomial; 87 | else 88 | entry = entry >> 1; 89 | createTable[i] = entry; 90 | } 91 | 92 | if (polynomial == DefaultPolynomial) 93 | _defaultTable = createTable; 94 | 95 | return createTable; 96 | } 97 | 98 | private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, byte[] buffer, int start, int size) 99 | { 100 | UInt32 crc = seed; 101 | for (int i = start; i < size; i++) 102 | unchecked 103 | { 104 | crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff]; 105 | } 106 | return crc; 107 | } 108 | 109 | private byte[] UInt32ToBigEndianBytes(UInt32 x) 110 | { 111 | return new[] 112 | { 113 | (byte) ((x >> 24) & 0xff), 114 | (byte) ((x >> 16) & 0xff), 115 | (byte) ((x >> 8) & 0xff), 116 | (byte) (x & 0xff) 117 | }; 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /BattleNET/Helpers.cs: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * BattleNET v1.3.4 - BattlEye Library and Client * 3 | * * 4 | * Copyright (C) 2018 by it's authors. * 5 | * Some rights reserved. See license.txt, authors.txt. * 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Globalization; 11 | using System.Reflection; 12 | using System.Text; 13 | 14 | namespace BattleNET 15 | { 16 | internal class Helpers 17 | { 18 | public static string Hex2Ascii(string hexString) 19 | { 20 | var j = 0; 21 | var tmp = new byte[(hexString.Length) / 2]; 22 | for (var i = 0; i <= hexString.Length - 2; i += 2) 23 | { 24 | tmp[j] = (byte)Convert.ToChar(Int32.Parse(hexString.Substring(i, 2), NumberStyles.HexNumber)); 25 | 26 | j++; 27 | } 28 | return Bytes2String(tmp); 29 | } 30 | 31 | public static byte[] String2Bytes(string s) 32 | { 33 | return Encoding.GetEncoding(1252).GetBytes(s); 34 | } 35 | 36 | public static string Bytes2String(byte[] bytes) 37 | { 38 | return Encoding.GetEncoding(1252).GetString(bytes); 39 | } 40 | 41 | public static string Bytes2String(byte[] bytes, int index, int count) 42 | { 43 | return Encoding.UTF8.GetString(bytes, index, count); 44 | } 45 | 46 | public static string StringValueOf(Enum value) 47 | { 48 | FieldInfo fi = value.GetType().GetField(value.ToString()); 49 | var attributes = 50 | (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 51 | if (attributes.Length > 0) 52 | { 53 | return attributes[0].Description; 54 | } 55 | else 56 | { 57 | return value.ToString(); 58 | } 59 | } 60 | 61 | public static object EnumValueOf(string value, Type enumType) 62 | { 63 | string[] names = Enum.GetNames(enumType); 64 | foreach (string name in names) 65 | { 66 | if (StringValueOf((Enum)Enum.Parse(enumType, name)).Equals(value)) 67 | { 68 | return Enum.Parse(enumType, name); 69 | } 70 | } 71 | 72 | throw new ArgumentException("The string is not a description or value of the specified enum."); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BattleNET [![NuGet](https://img.shields.io/nuget/v/BattleNET.svg)](https://www.nuget.org/packages/BattleNET/) # 2 | 3 | BattleNET is a C# (.NET) library and client for the BattlEye protocol. 4 | 5 | #### Source code content #### 6 | 7 | ``` 8 | BattleNET - The library 9 | BattleNET client - The client 10 | authors.txt - BattleNET authors 11 | BattleNET.sln - BattleNET solution 12 | changelog.txt - Changes made to BattleNET 13 | license.txt - The LGPL license 14 | README.md - This file 15 | ``` 16 | 17 | #### BattleNET client #### 18 | 19 | The BattleNET client basically replicates the official BE RCon client but uses the BattleNET library to do all of it's work. 20 | 21 | Usage: 22 | 23 | ``` 24 | BattleNET client.exe -host [ipaddress] -port [portnumber] -password [password] -command [command] 25 | ``` 26 | Command line options: 27 | ``` 28 | -host [ipaddress] RCon ip address 29 | -port [portnumber] RCon port number 30 | -password [password] RCon password 31 | -command [command] Sends command to RCon server and exits again 32 | Note: If no arguments are specified the client will ask for the login details. 33 | ``` 34 | 35 | Examples: 36 | 37 | ``` 38 | BattleNET client.exe -host 127.0.0.1 -port 2302 -password 123456789 39 | BattleNET client.exe -host 127.0.0.1 -port 2302 -password 123456789 -command "say -1 Hello World!" 40 | ``` 41 | 42 | #### BattleNET library #### 43 | 44 | Implementation sample: 45 | https://github.com/ziellos2k/BattleNET/blob/master/BattleNET%20client/Program.cs 46 | -------------------------------------------------------------------------------- /authors.txt: -------------------------------------------------------------------------------- 1 | Marcel de Vries 2 | Robert van der Boorn 3 | -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | v1.3.4 2 | * Convert thread to async method (https://github.com/tym32167) 3 | * Move to .NET Standard 2.0 (https://github.com/tym32167) 4 | * Limit connection attempts to 100 to get rid of the stack overflow issue (https://github.com/tym32167) 5 | 6 | v1.3.3 7 | * Improved command queuing system (Fixes #37) 8 | 9 | v1.3.2 10 | * Fixed an issue with banlists (Thank you DomiStyle) 11 | * Added "admins" command, which returns all connected RCon clients (Thank you maca134) 12 | 13 | v1.3.1 14 | * Fixed an issue where the (first) command would be sent twice 15 | * Fixed an issue where the library would lose connection after a long time, depending on server load (Thanks to EPM Cortez for finding the issue) 16 | 17 | v1.3 18 | * Client now has DNS support 19 | * BattlEyeLoginCredentials.Host changed from string to IPAddress 20 | * Increased timeout check sleep a bit (1 second) 21 | * Increased time before a packet gets resend (2 seconds) 22 | * Proper UTF8 support 23 | * The usual bugfixes and cleanups 24 | 25 | v1.2.1 26 | * Increased max socket receive buffer (fixes long ban lists) 27 | 28 | v1.2 29 | * Removed system messages (Connected, Disconnected, etc) from library 30 | * Changed ReconnectOnPacketLoss and IsConnected to properties 31 | * New connect event (success, invalid login, host unreachable) 32 | * SendCommandPacket() now returns an identifier which can be used in message filtering 33 | * Renamed SendCommandPacket() to SendCommand(), kinda... 34 | * Bugfixes and cleanups 35 | 36 | v1.1 37 | * Different method to construct packets 38 | * Some fixes and cleanups 39 | * Did licensing the right way 40 | 41 | v1.0.2 42 | * Fixed predefined commands, they now work actually. :) 43 | 44 | v1.0.1 45 | * Fixed a bug where the lib would send the 'say' command twice 46 | 47 | v1.0 48 | * Started using proper version numbers... :) 49 | 50 | 20121217.1 51 | * Library didn't reconnect on connection loss 52 | 53 | 20121217 54 | * Updated predifined commands 55 | * Timeout values decreased for faster connection drop detection 56 | * UTF8 support 57 | * Better handling of dropped packets (client -> server) 58 | * Packet receiving is now asynchronous 59 | * Some other fixes and cleanups 60 | * Client now accepts command line arguments 61 | 62 | 20120821 63 | * Hackish fix for not handling very long ban files 64 | 65 | 20120717 66 | * Decreased keep alive packet interval and timeout timer 67 | * Changed Encoding.Default to Encoding.GetEncoding(1252) as Default is variable across systems (also makes it compatible with Linux/mono) 68 | 69 | 20120706 70 | * Fixed autoreconnect not working 71 | 72 | 20120704 73 | * License added 74 | 75 | 20120628 76 | * Complete BattlEye protocol implementation 77 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | --------------------------------------------------------------------------------