Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Namespace Query
Class RCONQuery
Private qSocket As Socket
Private address As IPAddress
Private _port As Integer = 0
Private _password As String = Nothing
Private results As String() = New String(49) {}
Private _count As Integer = 0
Public Sub New(IP As String, port As Integer, password As String)
qSocket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
qSocket.SendTimeout = 5000
qSocket.ReceiveTimeout = 5000
Try
address = Dns.GetHostAddresses(IP)(0)
Catch
End Try
_port = port
_password = password
End Sub
Public Function Send(command As String) As Boolean
Try
Dim endpoint As New IPEndPoint(address, _port)
Using stream As New MemoryStream()
Using writer As New BinaryWriter(stream)
writer.Write("SAMP".ToCharArray())
Dim SplitIP As String() = address.ToString().Split("."C)
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(0))))
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(1))))
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(2))))
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(3))))
writer.Write(CUShort(_port))
writer.Write("x"C)
writer.Write(CUShort(_password.Length))
writer.Write(_password.ToCharArray())
writer.Write(CUShort(command.Length))
writer.Write(command.ToCharArray())
End Using
If qSocket.SendTo(stream.ToArray(), endpoint) > 0 Then
Return True
End If
End Using
Catch
Return False
End Try
Return False
End Function
Public Function Rceive() As Integer
Try
For i As Integer = 0 To results.GetLength(0) - 1
results.SetValue(Nothing, i)
Next
_count = 0
Dim endpoint As EndPoint = New IPEndPoint(address, _port)
Dim rBuffer As Byte() = New Byte(499) {}
Dim count As Integer = qSocket.ReceiveFrom(rBuffer, endpoint)
Using stream As New MemoryStream(rBuffer)
Using reader As New BinaryReader(stream)
If stream.Length <= 11 Then
Return _count
End If
reader.ReadBytes(11)
Dim len As Short
Try
While (InlineAssignHelper(len, reader.ReadInt16())) <> 0
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(Convert.ToInt32(len)))
End While
Catch
Return _count
End Try
End Using
End Using
Catch
Return _count
End Try
Return _count
End Function
Public Function Store(count As Integer) As String()
Dim rString As String() = New String(count - 1) {}
Dim i As Integer = 0
While i < count AndAlso i < _count
rString(i) = results(i)
i += 1
End While
_count = 0
Return rString
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
Class Query
Private qSocket As Socket
Private address As IPAddress
Private _port As Integer = 0
Private results As String()
Private _count As Integer = 0
Private timestamp As DateTime() = New DateTime(1) {}
Public Sub New(IP As String, port As Integer)
qSocket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
qSocket.SendTimeout = 5000
qSocket.ReceiveTimeout = 5000
Try
address = Dns.GetHostAddresses(IP)(0)
Catch
End Try
_port = port
End Sub
Public Function Send(opcode As Char) As Boolean
Try
Dim endpoint As EndPoint = New IPEndPoint(address, _port)
Using stream As New MemoryStream()
Using writer As New BinaryWriter(stream)
writer.Write("SAMP".ToCharArray())
Dim SplitIP As String() = address.ToString().Split("."C)
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(0))))
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(1))))
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(2))))
writer.Write(Convert.ToByte(Convert.ToInt32(SplitIP(3))))
writer.Write(CUShort(_port))
writer.Write(opcode)
If opcode = "p"C Then
writer.Write("8493".ToCharArray())
End If
timestamp(0) = DateTime.Now
End Using
If qSocket.SendTo(stream.ToArray(), endpoint) > 0 Then
Return True
End If
End Using
Catch
Return False
End Try
Return False
End Function
Public Function Receive() As Integer
Try
_count = 0
Dim endpoint As EndPoint = New IPEndPoint(address, _port)
Dim rBuffer As Byte() = New Byte(3401) {}
qSocket.ReceiveFrom(rBuffer, endpoint)
timestamp(1) = DateTime.Now
Using stream As New MemoryStream(rBuffer)
Using reader As New BinaryReader(stream)
If stream.Length <= 10 Then
Return _count
End If
reader.ReadBytes(10)
Select Case reader.ReadChar()
Case "i"C
' Information
If True Then
results = New String(5) {}
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadByte())
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadInt16())
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadInt16())
Dim hostnamelen As Integer = reader.ReadInt32()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(hostnamelen))
Dim gamemodelen As Integer = reader.ReadInt32()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(gamemodelen))
Dim mapnamelen As Integer = reader.ReadInt32()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(mapnamelen))
Return _count
End If
Case "r"C
' Rules
If True Then
Dim rulecount As Integer = reader.ReadInt16()
results = New String(rulecount * 2 - 1) {}
For i As Integer = 0 To rulecount - 1
Dim rulelen As Integer = reader.ReadByte()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(rulelen))
Dim valuelen As Integer = reader.ReadByte()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(valuelen))
Next
Return _count
End If
Case "c"C
' Client list
If True Then
Dim playercount As Integer = reader.ReadInt16()
results = New String(playercount * 2 - 1) {}
For i As Integer = 0 To playercount - 1
Dim namelen As Integer = reader.ReadByte()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(namelen))
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadInt32())
Next
Return _count
End If
Case "d"C
' Detailed player information
If True Then
Dim playercount As Integer = reader.ReadInt16()
results = New String(playercount * 4 - 1) {}
For i As Integer = 0 To playercount - 1
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadByte())
Dim namelen As Integer = reader.ReadByte()
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = New String(reader.ReadChars(namelen))
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadInt32())
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = Convert.ToString(reader.ReadInt32())
Next
Return _count
End If
Case "p"C
' Ping
If True Then
results = New String(0) {}
results(System.Math.Max(System.Threading.Interlocked.Increment(_count),_count - 1)) = timestamp(1).Subtract(timestamp(0)).Milliseconds.ToString()
Return _count
End If
Case Else
Return _count
End Select
End Using
End Using
Catch
Return _count
End Try
End Function
Public Function Store(count As Integer) As String()
Dim rString As String() = New String(count - 1) {}
Dim i As Integer = 0
While i < count AndAlso i < _count
rString(i) = results(i)
i += 1
End While
_count = 0
Return rString
End Function
End Class
End Namespace