Ich hab mal vor einiger zeit ein HLSW ähnliches Tool geschrieben und ich hab mir jetzt gedacht, dass sich daraus relativ leicht eine UDF schreiben lässt.
Die UDF enthält folgende Befehle:
- _SourceConnect()
Verbindet sich mit einem SourceServer
- _SourceGetChallenge()
Gibt eine challenge number zurück, die für _SourceGetPlayers() und _SourceGetRules() benötigt wird
- _SourceGetInfo(), _SourceGetPlayers(), _SourceGetRules()
Geben jeweils ein Array zurück, das nur mit Hilfe dieser Seite verstanden werden kann:
- _SourceClose()
Schließt die offene Verbindung
Getestet habe ich bisher nur Counterstrike Source Server, aber es sollten prinzipiell alle SourceGames gehen.
Falls hier überhaupt Leute unterwegs sein sollten, die so etwas interessiert, würd ich mich über Feedback freuen!
UDF:
Spoiler anzeigen
#include <Array.au3>
[/autoit] [autoit][/autoit] [autoit]Const $S2C_CHALLENGE = Binary("0xFFFFFFFF56FFFFFFFF")
Const $A2S_RULES = Binary("0xFFFFFFFF56")
Const $A2S_PLAYER = Binary("0xFFFFFFFF55")
Const $A2S_INFO = Binary("0xFFFFFFFF54536F7572636520456E67696E6520517565727900")
Global $g_PING = 0, $socket
; ////////////////////// Functions \\\\\\\\\\\\\\\\\\\\\\
; ===================\
;_SourceConnect
;_SourceGetChallenge
;_SourceGetInfo
;_SourceGetPlayers
;_SourceGetRules
;_SourceClose
;
;__SourceReceiveData
;__SourceBinaryToArray
; ===================/
; #FUNCTION# ====================================================================================================================
; Name ..........: _SourceConnect
; Description ...: Baut ein Verbindung zum Server auf
; Syntax ........: _SourceConnect($sIP)
; Parameters ....: $sIP - A string value.
; Return values .: Socket
; ===============================================================================================================================
Func _SourceConnect($sIP)
UDPStartup()
$aIP = StringRegExp($sIP, "([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\:([0-9]{1,6})", 3)
If Not IsArray($aIP) Then
MsgBox(4112, "Error", "Keine gültige Ip-Addresse!")
Return
EndIf
Local $socket = UDPOpen($aIP[0], $aIP[1])
If @error Then
MsgBox(4112, "Error", "UDPOpen failed with WSA error: " & @error)
Exit
EndIf
Return $socket
EndFunc ;==>_SourceConnect
; #FUNCTION# ====================================================================================================================
; Name ..........: _SourceGetChallenge
; Description ...: Empfängt die Challenge Number
; Syntax ........: _SourceGetChallenge($socket[, $iTimeOut = 2000])
; Parameters ....: $socket - A string value.
; $iTimeOut - [optional] An integer value. Default is 2000.
; Return values .: On Success - Returns Binary
; Timeout - -1
; ===============================================================================================================================
Func _SourceGetChallenge($socket, $iTimeOut = 2000)
Local $timer = TimerInit()
UDPSend($socket, $S2C_CHALLENGE)
Do
Local $data = Binary(UDPRecv($socket, 50))
If $data <> "" And BinaryLen($data) = 9 Then Return BinaryMid($data, 6)
Sleep(10)
Until TimerDiff($timer) > $iTimeOut
Return -1
EndFunc ;==>_SourceGetChallenge
; #FUNCTION# ====================================================================================================================
; Name ..........: _SourceGetInfo
; Description ...: Empfängt die Serverinfo
; Syntax ........: _SourceGetInfo($socket)
; Parameters ....: $socket - A string value.
; Return values .: Array
Func _SourceGetInfo($socket)
UDPSend($socket, $A2S_INFO)
Return __SourceBinaryToArray(__SourceReceiveData($socket), 'nnnhhssssiniiicchhs')
EndFunc ;==>_SourceGetInfo
; #FUNCTION# ====================================================================================================================
; Name ..........: _SourceGetPlayers
; Description ...: Empfängt die Spielerdaten
; Syntax ........: _SourceGetPlayers($socket, $bChallenge)
; Parameters ....: $socket - A string value.
; $bChallenge - A binary value.
; Return values .: Array
; ===============================================================================================================================
Func _SourceGetPlayers($socket, $bChallenge)
UDPSend($socket, $A2S_PLAYER + $bChallenge)
Local $sRecv = __SourceReceiveData($socket)
Local $iCount = Int(BinaryMid($sRecv, 6, 1))
If $iCount = 0 Then Return 0
Local $sPattern = "nnnnn"
For $iI = 1 To $iCount
$sPattern &= "nslf"
Next
Return __SourceBinaryToArray($sRecv, $sPattern)
EndFunc ;==>_SourceGetPlayers
; #FUNCTION# ====================================================================================================================
; Name ..........: _SourceGetRules
; Description ...: Empfängt die Server Rules
; Syntax ........: _SourceGetRules($socket, $bChallenge)
; Parameters ....: $socket - A string value.
; $bChallenge - A binary value.
; Return values .: Array
; ===============================================================================================================================
Func _SourceGetRules($socket, $bChallenge)
UDPSend($socket, $A2S_RULES + $bChallenge)
Local $iCount, $sPattern
Local $sRecv = __SourceReceiveData($socket)
If StringLeft($sRecv, 4) = "0xFE" Then
$iCount = Int(BinaryMid($sRecv, 18, 1))
$sPattern = "nnnnnnnnnnnnnnnnnn"
Else
$iCount = Int(BinaryMid($sRecv, 6, 1))
$sPattern = "nn"
EndIf
For $iI = 1 To $iCount
$sPattern &= "ss"
Next
Return __SourceBinaryToArray($sRecv, $sPattern)
EndFunc ;==>_SourceGetRules
; #FUNCTION# ====================================================================================================================
; Name ..........: __SourceReceiveData
; Description ...: Empfängt ein oder mehrere Pakete und gibt diese als String aus
; Syntax ........: __SourceReceiveData($socket[, $iTimeOut = 2000])
; Parameters ....: $socket - A string value.
; $iTimeOut - [optional] An integer value. Default is 2000.
; Return values .: On Success - Returns String
; Timeout - -1
; ===============================================================================================================================
Func __SourceReceiveData($socket, $iTimeOut = 2000)
Local $timer = TimerInit()
Do
Local $sString = Binary(UDPRecv($socket, 2048))
If $sString <> '' Then
$g_PING = Round(TimerDiff($timer), 2) & " ms"
If BinaryMid($sString, 1, 4) = "0xFEFFFFFF" Then ; Falls das Paket in mehrere Parts gesplittet ist
Local $iPacketCount = Int(BinaryMid($sString, 9, 1))
For $iCurrentPacket = 1 To $iPacketCount ; Alle Pakete zusammenfügen
$sChunk = UDPRecv($socket, 2048)
If $sChunk <> '' Then $sString &= BinaryMid(Binary($sChunk), 0xD)
If TimerDiff($timer) > $iTimeOut Then Return -1
Next
Return $sString
Else
Return $sString
EndIf
EndIf
Sleep(10)
Until TimerDiff($timer) > $iTimeOut
Return -1
EndFunc ;==>__SourceReceiveData
; #FUNCTION# ====================================================================================================================
; Name ..........: __SourceBinaryToArray
; Description ...: Splittet einen BinaryString nach einem bestimmten Pattern
; Syntax ........: __SourceBinaryToArray($sString, $sPattern)
; Parameters ....: $sString - A string value.
; $sPattern - Zeichenfolge
; i = 1 Byte als Ganzzahl
; h = 1 Byte in Hexschreibweise
; c = 1 Byte als Char
; l = long (32bit signed BigEndian)
; f = float (32bit BigEndian)
; s = Null-terminated String
; n = Null Byte (ein Byte überspringen)
; Return values .: None
; Author ........: Your Name
; Modified ......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func __SourceBinaryToArray($sString, $sPattern)
Local $iByte = 3, $aBytes = StringSplit(StringTrimLeft($sString, 2), ""), $aPattern = StringSplit($sPattern, ""), $aResult[1]
For $iType = 1 To $aPattern[0]
Switch $aPattern[$iType]
Case "i"
_ArrayAdd($aResult, Int("0x" & $aBytes[$iByte] & $aBytes[$iByte + 1]))
$iByte += 2
Case "h"
_ArrayAdd($aResult, "0x" & $aBytes[$iByte] & $aBytes[$iByte + 1])
$iByte += 2
Case "c"
_ArrayAdd($aResult, Chr("0x" & $aBytes[$iByte] & $aBytes[$iByte + 1]))
$iByte += 2
Case "l"
Local $iLong = 0
For $iI = 6 To 0 Step -2
$iLong &= $aBytes[$iByte + $iI] & $aBytes[$iByte + $iI + 1]
Next
_ArrayAdd($aResult, Dec($iLong))
$iByte += 8
Case "f"
Local $iFloat = ""
For $iI = 6 To 0 Step -2
$iFloat &= $aBytes[$iByte + $iI] & $aBytes[$iByte + $iI + 1]
Next
Local $tInt = DllStructCreate("int")
Local $tFloat = DllStructCreate("float", DllStructGetPtr($tInt))
DllStructSetData($tInt, 1, Dec($iFloat))
_ArrayAdd($aResult, DllStructGetData($tFloat, 1))
$iByte += 8
Case "s"
Local $sChunk = "0x"
Local $sCurrentChar = $aBytes[$iByte] & $aBytes[$iByte + 1]
While $sCurrentChar <> "00"
$sChunk &= $sCurrentChar
$iByte += 2
$sCurrentChar = $aBytes[$iByte] & $aBytes[$iByte + 1]
WEnd
_ArrayAdd($aResult, BinaryToString($sChunk, 4))
$iByte += 2
Case "n"
$iByte += 2
EndSwitch
Next
$aResult[0] = UBound($aResult) - 1
Return $aResult
EndFunc ;==>__SourceBinaryToArray
; #FUNCTION# ====================================================================================================================
; Name ..........: _SourceClose
; Description ...: Schließt die offene UDP-Verbindung
; Syntax ........: _SourceClose()
; ===============================================================================================================================
Func _SourceClose($socket)
UDPCloseSocket($socket)
UDPShutdown()
EndFunc ;==>_SourceClose
Testscript:
Spoiler anzeigen
#include "steam.au3"
[/autoit] [autoit][/autoit] [autoit]$socket = _SourceConnect("77.111.213.213:27015")
$bChallenge = _SourceGetChallenge($socket)
$aInfo = _SourceGetInfo($socket)
$aRules = _SourceGetRules($socket, $bChallenge)
$aPlayers = _SourceGetPlayers($socket, $bChallenge)
_ArrayDisplay($aInfo)
_ArrayDisplay($aRules)
_ArrayDisplay($aPlayers)
MsgBox(0, "", $g_PING)
_SourceClose($socket)
K4z