Difference between revisions of "How to RCON a source engine based server"
From Scriptwiki
m (See also) |
m (Fixed some stuff to not override other scripts) |
||
Line 11: | Line 11: | ||
; Usage: | ; Usage: | ||
; * /sourcercon <ip> <port> <pass> | ; * /sourcercon <ip> <port> <pass> | ||
− | + | ||
; Define a prefix for sockent names. | ; Define a prefix for sockent names. | ||
[[alias]] -l srcon.prefix { [[return]] SRcon } | [[alias]] -l srcon.prefix { [[return]] SRcon } | ||
− | + | ||
; Set the command requests and response types. | ; Set the command requests and response types. | ||
[[alias]] -l srcon.req.execcmd { [[return]] 2 } | [[alias]] -l srcon.req.execcmd { [[return]] 2 } | ||
Line 20: | Line 20: | ||
[[alias]] -l srcon.res.cmd { [[return]] 0 } | [[alias]] -l srcon.res.cmd { [[return]] 0 } | ||
[[alias]] -l srcon.res.auth { [[return]] 2 } | [[alias]] -l srcon.res.auth { [[return]] 2 } | ||
− | + | ||
; Turn the given number to a 4-byte number. | ; Turn the given number to a 4-byte number. | ||
[[alias]] -l srcon.inttobytes { | [[alias]] -l srcon.inttobytes { | ||
Line 26: | Line 26: | ||
[[return]] [[$1-|$4]] [[$1-|$3]] [[$1-|$2]] [[$1-|$1]] | [[return]] [[$1-|$4]] [[$1-|$3]] [[$1-|$2]] [[$1-|$1]] | ||
} | } | ||
− | + | ||
; Validates arguments and tries to open the socket to the game server for authentication. | ; Validates arguments and tries to open the socket to the game server for authentication. | ||
[[alias]] sourcercon { | [[alias]] sourcercon { | ||
Line 34: | Line 34: | ||
[[return]] | [[return]] | ||
} | } | ||
− | + | ||
; Save the server's address. | ; Save the server's address. | ||
[[Local_Variables|var]] %server.addr = [[DollarPlus|$+]]([[$1-|$1]],:,[[$1-|$2]]) | [[Local_Variables|var]] %server.addr = [[DollarPlus|$+]]([[$1-|$1]],:,[[$1-|$2]]) | ||
− | + | ||
; Check that the user has not opened a Rcon window for the same server already. | ; Check that the user has not opened a Rcon window for the same server already. | ||
; This makes sure that the user won't have a Rcon step over another Rcon for the same server. | ; This makes sure that the user won't have a Rcon step over another Rcon for the same server. | ||
Line 44: | Line 44: | ||
[[return]] | [[return]] | ||
} | } | ||
− | + | ||
; Open the Rcon window whilst activating it, with an editbox, hide the @ prefix and maximize it. | ; Open the Rcon window whilst activating it, with an editbox, hide the @ prefix and maximize it. | ||
window -aek0x @ [[DollarPlus|$+]] %server.addr | window -aek0x @ [[DollarPlus|$+]] %server.addr | ||
[[aline]] 12 @ [[DollarPlus|$+]] %server.addr Source RCON window. Type a command\cvar to send to the server, responses will be displayed here. | [[aline]] 12 @ [[DollarPlus|$+]] %server.addr Source RCON window. Type a command\cvar to send to the server, responses will be displayed here. | ||
[[aline]] 12 @ [[DollarPlus|$+]] %server.addr Warning! commands like exit or quit will close the server! avoid using them! | [[aline]] 12 @ [[DollarPlus|$+]] %server.addr Warning! commands like exit or quit will close the server! avoid using them! | ||
− | + | ||
; Set the socket name we'll use. | ; Set the socket name we'll use. | ||
[[Local_Variables|var]] %sockname = [[DollarPlus|$+]]($srcon.prefix,%server.addr) | [[Local_Variables|var]] %sockname = [[DollarPlus|$+]]($srcon.prefix,%server.addr) | ||
− | + | ||
; Open the socket to the server. | ; Open the socket to the server. | ||
[[sockopen]] %sockname [[$1-|$1]] [[$1-|$2]] | [[sockopen]] %sockname [[$1-|$1]] [[$1-|$2]] | ||
− | + | ||
; Mark the socket with the Rcon password. | ; Mark the socket with the Rcon password. | ||
[[sockmark]] %sockname [[$1-|$3]] | [[sockmark]] %sockname [[$1-|$3]] | ||
} | } | ||
− | + | ||
; Catch all sockopens with the Source Rcon sockets prefix. | ; Catch all sockopens with the Source Rcon sockets prefix. | ||
; Build the authentication request packet and send it to the server. | ; Build the authentication request packet and send it to the server. | ||
Line 65: | Line 65: | ||
; Initialize the request ID for the connection. | ; Initialize the request ID for the connection. | ||
[[set]] %srcon.id. [[DollarPlus|$+]] [[$sockname]] 0 | [[set]] %srcon.id. [[DollarPlus|$+]] [[$sockname]] 0 | ||
− | + | ||
; Constructed auth request to send to the server. | ; Constructed auth request to send to the server. | ||
srcon.getrequest &srcon.auth %srcon.id. [ [[DollarPlus|$+]] [ [[$sockname]] ] ] $srcon.req.auth [[$sock]]([[$sockname]]).mark | srcon.getrequest &srcon.auth %srcon.id. [ [[DollarPlus|$+]] [ [[$sockname]] ] ] $srcon.req.auth [[$sock]]([[$sockname]]).mark | ||
− | + | ||
; Send the authentication packet. | ; Send the authentication packet. | ||
[[sockwrite]] [[$sockname]] &srcon.auth | [[sockwrite]] [[$sockname]] &srcon.auth | ||
} | } | ||
− | + | ||
; Read data from the game server. | ; Read data from the game server. | ||
on *:SOCKREAD:$([[DollarPlus|$+]]($srcon.prefix, *)): { | on *:SOCKREAD:$([[DollarPlus|$+]]($srcon.prefix, *)): { | ||
; Get the window name for the current game server. | ; Get the window name for the current game server. | ||
[[Local_Variables|var]] %srcon.window = [[DollarPlus|$+]](@, [[$remove]]([[$sockname]], $srcon.prefix)) | [[Local_Variables|var]] %srcon.window = [[DollarPlus|$+]](@, [[$remove]]([[$sockname]], $srcon.prefix)) | ||
− | + | ||
; If there were errors, $sockerr will tell us so. | ; If there were errors, $sockerr will tell us so. | ||
; Write the error message to the window and clear the connection. | ; Write the error message to the window and clear the connection. | ||
Line 85: | Line 85: | ||
[[return]] | [[return]] | ||
} | } | ||
− | + | ||
; If a prior packet didn't finish receiving, continue reading it. | ; If a prior packet didn't finish receiving, continue reading it. | ||
[[If-Then-Else|if]] ([[$hget]]([[$sockname]])) { | [[If-Then-Else|if]] ([[$hget]]([[$sockname]])) { | ||
; Set the packet size. | ; Set the packet size. | ||
[[Local_Variables|var]] %srcon.pckt.size = [[$hget]]([[$sockname]], size) | [[Local_Variables|var]] %srcon.pckt.size = [[$hget]]([[$sockname]], size) | ||
− | + | ||
; Set the number of bytes left to read. | ; Set the number of bytes left to read. | ||
[[Local_Variables|var]] %srcon.pckt.left = [[$hget]]([[$sockname]], left) | [[Local_Variables|var]] %srcon.pckt.left = [[$hget]]([[$sockname]], left) | ||
− | + | ||
; Set the request id. | ; Set the request id. | ||
[[Local_Variables|var]] %srcon.pckt.id = [[$hget]]([[$sockname]], id) | [[Local_Variables|var]] %srcon.pckt.id = [[$hget]]([[$sockname]], id) | ||
− | + | ||
; Set the command response type. | ; Set the command response type. | ||
[[Local_Variables|var]] %srcon.pckt.cmd = [[$hget]]([[$sockname]], cmd) | [[Local_Variables|var]] %srcon.pckt.cmd = [[$hget]]([[$sockname]], cmd) | ||
− | + | ||
; Set the cut string1. | ; Set the cut string1. | ||
[[noop]] [[$hget]]([[$sockname]], string1, &srcon.pckt.string1) | [[noop]] [[$hget]]([[$sockname]], string1, &srcon.pckt.string1) | ||
− | + | ||
; Read the rest of string1. | ; Read the rest of string1. | ||
[[Sockread|sockread]] %srcon.pckt.left &srcon.pckt.rest | [[Sockread|sockread]] %srcon.pckt.left &srcon.pckt.rest | ||
[[dec]] %srcon.pckt.left $sockbr | [[dec]] %srcon.pckt.left $sockbr | ||
− | + | ||
; Append the rest of string1 to the already received string1. | ; Append the rest of string1 to the already received string1. | ||
[[bcopy]] &srcon.pckt.string1 [[$calc]]([[$bvar]](&srcon.pckt.string1, 0) + 1) &srcon.pckt.rest 1 -1 | [[bcopy]] &srcon.pckt.string1 [[$calc]]([[$bvar]](&srcon.pckt.string1, 0) + 1) &srcon.pckt.rest 1 -1 | ||
− | + | ||
; Clear the un-needed variables. | ; Clear the un-needed variables. | ||
[[hfree]] [[$sockname]] | [[hfree]] [[$sockname]] | ||
Line 118: | Line 118: | ||
[[Sockread|sockread]] 4 &srcon.pckt.size | [[Sockread|sockread]] 4 &srcon.pckt.size | ||
[[Local_Variables|var]] %srcon.pckt.size = [[$bvar]](&srcon.pckt.size, 1).long | [[Local_Variables|var]] %srcon.pckt.size = [[$bvar]](&srcon.pckt.size, 1).long | ||
− | + | ||
; Initialize the number of bytes left to read. | ; Initialize the number of bytes left to read. | ||
[[Local_Variables|var]] %srcon.pckt.left = %srcon.pckt.size | [[Local_Variables|var]] %srcon.pckt.left = %srcon.pckt.size | ||
− | + | ||
; Read the packet id. | ; Read the packet id. | ||
[[Sockread|sockread]] 4 &srcon.pckt.id | [[Sockread|sockread]] 4 &srcon.pckt.id | ||
[[Local_Variables|var]] %srcon.pckt.id = [[$bvar]](&srcon.pckt.id, 1).long | [[Local_Variables|var]] %srcon.pckt.id = [[$bvar]](&srcon.pckt.id, 1).long | ||
[[dec]] %srcon.pckt.left $sockbr | [[dec]] %srcon.pckt.left $sockbr | ||
− | + | ||
; If the request id is an error, stop processing, display an error and clear the connection. | ; If the request id is an error, stop processing, display an error and clear the connection. | ||
[[If-Then-Else|if]] ($srcon.inttobytes(%srcon.pckt.id) == 255 255 255 255) { | [[If-Then-Else|if]] ($srcon.inttobytes(%srcon.pckt.id) == 255 255 255 255) { | ||
Line 133: | Line 133: | ||
[[return]] | [[return]] | ||
} | } | ||
− | + | ||
; Read the packet command response type. | ; Read the packet command response type. | ||
[[Sockread|sockread]] 4 &srcon.pckt.cmd | [[Sockread|sockread]] 4 &srcon.pckt.cmd | ||
[[Local_Variables|var]] %srcon.pckt.cmd = [[$bvar]](&srcon.pckt.cmd, 1).long | [[Local_Variables|var]] %srcon.pckt.cmd = [[$bvar]](&srcon.pckt.cmd, 1).long | ||
[[dec]] %srcon.pckt.left $sockbr | [[dec]] %srcon.pckt.left $sockbr | ||
− | + | ||
; Read string1. | ; Read string1. | ||
[[Sockread|sockread]] %srcon.pckt.left &srcon.pckt.string1 | [[Sockread|sockread]] %srcon.pckt.left &srcon.pckt.string1 | ||
[[dec]] %srcon.pckt.left $sockbr | [[dec]] %srcon.pckt.left $sockbr | ||
} | } | ||
− | + | ||
; If the number of bytes left to read is still positive, the packet was splitted. | ; If the number of bytes left to read is still positive, the packet was splitted. | ||
; This means that we'll save the variables to globals so it can be used in the next read. | ; This means that we'll save the variables to globals so it can be used in the next read. | ||
Line 166: | Line 166: | ||
; Convert the binary string1 to a usable variable. | ; Convert the binary string1 to a usable variable. | ||
[[Local_Variables|var]] %srcon.pckt.string1 = [[$bvar]](&srcon.pckt.string1, 1, [[$bvar]](&srcon.pckt.string1, 0)).text | [[Local_Variables|var]] %srcon.pckt.string1 = [[$bvar]](&srcon.pckt.string1, 1, [[$bvar]](&srcon.pckt.string1, 0)).text | ||
− | + | ||
; Tokenize the lines to be printed and print them. | ; Tokenize the lines to be printed and print them. | ||
[[tokenize]] [[$asc]]([[$lf]]) %srcon.pckt.string1 | [[tokenize]] [[$asc]]([[$lf]]) %srcon.pckt.string1 | ||
Line 173: | Line 173: | ||
} | } | ||
} | } | ||
− | + | ||
; Sockets may close on their own if not kept alive. | ; Sockets may close on their own if not kept alive. | ||
; In case that happens when the window is still open, the socket will be reopened. | ; In case that happens when the window is still open, the socket will be reopened. | ||
Line 179: | Line 179: | ||
; Get the window name for the current game server. | ; Get the window name for the current game server. | ||
[[Local_Variables|var]] %srcon.window = [[DollarPlus|$+]](@, [[$remove]]([[$sockname]], $srcon.prefix)) | [[Local_Variables|var]] %srcon.window = [[DollarPlus|$+]](@, [[$remove]]([[$sockname]], $srcon.prefix)) | ||
− | + | ||
; If the window and the current request id still exists, reopen the socket. | ; If the window and the current request id still exists, reopen the socket. | ||
[[If-Then-Else|if]] (([[$window_(remote)|$window(]]%srcon.window)) && (%srcon.id. [ [[DollarPlus|$+]] [ [[$sockname]] ] ])) { | [[If-Then-Else|if]] (([[$window_(remote)|$window(]]%srcon.window)) && (%srcon.id. [ [[DollarPlus|$+]] [ [[$sockname]] ] ])) { | ||
Line 187: | Line 187: | ||
%srcon.port = [[$sock]]([[$sockname]]).port | %srcon.port = [[$sock]]([[$sockname]]).port | ||
%srcon.pass = [[$sock]]([[$sockname]]).mark | %srcon.pass = [[$sock]]([[$sockname]]).mark | ||
− | + | ||
; Terminate the socket so it could be reopened. | ; Terminate the socket so it could be reopened. | ||
[[sockclose]] [[$sockname]] | [[sockclose]] [[$sockname]] | ||
− | + | ||
; Reopen the socket to the server. | ; Reopen the socket to the server. | ||
[[sockopen]] %srcon.name %srcon.ip %srcon.port | [[sockopen]] %srcon.name %srcon.ip %srcon.port | ||
− | + | ||
; Mark the socket with the Rcon password. | ; Mark the socket with the Rcon password. | ||
[[sockmark]] %srcon.name %srcon.pass | [[sockmark]] %srcon.name %srcon.pass | ||
} | } | ||
} | } | ||
− | + | ||
; Sends user input to the server as is. | ; Sends user input to the server as is. | ||
; NOTE: Commands like exit or quit will close the server! | ; NOTE: Commands like exit or quit will close the server! | ||
Line 204: | Line 204: | ||
; Get the socket name. | ; Get the socket name. | ||
[[Local_Variables|var]] %srcon.socket = [[DollarPlus|$+]]($srcon.prefix, [[$remove]]($target, @)) | [[Local_Variables|var]] %srcon.socket = [[DollarPlus|$+]]($srcon.prefix, [[$remove]]($target, @)) | ||
− | + | ||
+ | ; If the input is not for the Source Rcon window, ignore it. | ||
+ | [[If-Then-Else|if]] ([[$$|$]]([[DollarPlus|$+]](%, srcon.id., %srcon.socket), 2) == [[$null]]) { [[return]] } | ||
+ | |||
; Check if the socket is still alive. | ; Check if the socket is still alive. | ||
[[If-Then-Else|if]] (![[$sock]](%srcon.socket)) { | [[If-Then-Else|if]] (![[$sock]](%srcon.socket)) { | ||
Line 210: | Line 213: | ||
[[return]] | [[return]] | ||
} | } | ||
− | + | ||
; Build the execute command request packet and send it to the server. | ; Build the execute command request packet and send it to the server. | ||
− | + | ||
; Increment the current request id. | ; Increment the current request id. | ||
[[inc]] %srcon.id. [[DollarPlus|$+]] %srcon.socket | [[inc]] %srcon.id. [[DollarPlus|$+]] %srcon.socket | ||
− | + | ||
; Construct the request to send to the game server. | ; Construct the request to send to the game server. | ||
srcon.getrequest &srcon.cmd %srcon.id. [ [[DollarPlus|$+]] [ %srcon.socket ] ] $srcon.req.execcmd [[$1-|$1-]] | srcon.getrequest &srcon.cmd %srcon.id. [ [[DollarPlus|$+]] [ %srcon.socket ] ] $srcon.req.execcmd [[$1-|$1-]] | ||
− | + | ||
[[aline]] $target -> [[$1-|$1-]] | [[aline]] $target -> [[$1-|$1-]] | ||
− | + | ||
; Send the command request. | ; Send the command request. | ||
[[sockwrite]] %srcon.socket &srcon.cmd | [[sockwrite]] %srcon.socket &srcon.cmd | ||
} | } | ||
− | + | ||
; If the user has closed the rcon window, clear the socket. | ; If the user has closed the rcon window, clear the socket. | ||
on *:CLOSE:@: { | on *:CLOSE:@: { | ||
srcon.clear [[DollarPlus|$+]]($srcon.prefix, [[$remove]]($target, @)) | srcon.clear [[DollarPlus|$+]]($srcon.prefix, [[$remove]]($target, @)) | ||
} | } | ||
− | + | ||
; Constructs a request with the given parameters: | ; Constructs a request with the given parameters: | ||
; $1 = Bvar to store the request | ; $1 = Bvar to store the request | ||
Line 238: | Line 241: | ||
; Clear the given bvar to make sure it doesn't contain any preset values. | ; Clear the given bvar to make sure it doesn't contain any preset values. | ||
[[bunset]] [[$1-|$1]] | [[bunset]] [[$1-|$1]] | ||
− | + | ||
; Set the given request ID in the request. | ; Set the given request ID in the request. | ||
[[bset]] [[$1-|$1]] 5 $srcon.inttobytes([[$1-|$2]]) | [[bset]] [[$1-|$1]] 5 $srcon.inttobytes([[$1-|$2]]) | ||
− | + | ||
; Set the given request type. | ; Set the given request type. | ||
[[bset]] [[$1-|$1]] 9 $srcon.inttobytes([[$1-|$3]]) | [[bset]] [[$1-|$1]] 9 $srcon.inttobytes([[$1-|$3]]) | ||
− | + | ||
; Set string1 the request data. | ; Set string1 the request data. | ||
[[bset]] -t [[$1-|$1]] 13 [[$1-|$4-]] | [[bset]] -t [[$1-|$1]] 13 [[$1-|$4-]] | ||
− | + | ||
; Terminate string1 with 0x00 and set string2 to 0x00. | ; Terminate string1 with 0x00 and set string2 to 0x00. | ||
[[bset]] [[$1-|$1]] [[$calc]]([[$bvar]]([[$1-|$1]],0) + 1) 00 00 | [[bset]] [[$1-|$1]] [[$calc]]([[$bvar]]([[$1-|$1]],0) + 1) 00 00 | ||
− | + | ||
; Set the packet size. | ; Set the packet size. | ||
[[bset]] [[$1-|$1]] 1 $srcon.inttobytes([[$calc]]([[$bvar]]([[$1-|$1]], 0) - 4)) | [[bset]] [[$1-|$1]] 1 $srcon.inttobytes([[$calc]]([[$bvar]]([[$1-|$1]], 0) - 4)) | ||
} | } | ||
− | + | ||
; Clears the socket and the request id. | ; Clears the socket and the request id. | ||
[[alias]] -l srcon.clear { | [[alias]] -l srcon.clear { | ||
Line 261: | Line 264: | ||
[[sockclose]] [[$1-|$1]] | [[sockclose]] [[$1-|$1]] | ||
} | } | ||
− | + | ||
; Clear the id var. | ; Clear the id var. | ||
[[Unset|unset]] %srcon.id. [[DollarPlus|$+]] [[$1-|$1]] | [[Unset|unset]] %srcon.id. [[DollarPlus|$+]] [[$1-|$1]] | ||
Line 267: | Line 270: | ||
==See also== | ==See also== | ||
+ | * [[How to RCON a HL1 engine based server]] | ||
* [[How to query a CS Server]] | * [[How to query a CS Server]] | ||
* [[How to parse HL log data]] | * [[How to parse HL log data]] |
Revision as of 20:38, 11 June 2011
; Source RCON control snippet by NaNg ; Date: 12-02-2011 ; Tested on mIRC 7.14 ; ; Remote control window for Source engine based games (e.g. HL2, OrangeBox, CS:S, CSP etc.), ; based on the Source RCON Protocol found at http://developer.valvesoftware.com/wiki/Source_RCON_Protocol ; ; Warning! I couldn't find a perfect way to open the socket nicely everytime it closes, so don't rely on it ; to be connected 24/7 (plus, the socket is closed on the server side every changelevel). ; ; Usage: ; * /sourcercon <ip> <port> <pass> ; Define a prefix for sockent names. alias -l srcon.prefix { return SRcon } ; Set the command requests and response types. alias -l srcon.req.execcmd { return 2 } alias -l srcon.req.auth { return 3 } alias -l srcon.res.cmd { return 0 } alias -l srcon.res.auth { return 2 } ; Turn the given number to a 4-byte number. alias -l srcon.inttobytes { tokenize 46 $longip($1) return $4 $3 $2 $1 } ; Validates arguments and tries to open the socket to the game server for authentication. alias sourcercon { ; Validate arguments (simple, no need for full validation). if ((!$longip($1)) || ($2 !isnum 1-65536) || (!$3)) { echo -ag Invalid parameters. return } ; Save the server's address. var %server.addr = $+($1,:,$2) ; Check that the user has not opened a Rcon window for the same server already. ; This makes sure that the user won't have a Rcon step over another Rcon for the same server. if ($window(%server.addr)) { echo -ag Rcon window for $1 is already open! close it before trying. return } ; Open the Rcon window whilst activating it, with an editbox, hide the @ prefix and maximize it. window -aek0x @ $+ %server.addr aline 12 @ $+ %server.addr Source RCON window. Type a command\cvar to send to the server, responses will be displayed here. aline 12 @ $+ %server.addr Warning! commands like exit or quit will close the server! avoid using them! ; Set the socket name we'll use. var %sockname = $+($srcon.prefix,%server.addr) ; Open the socket to the server. sockopen %sockname $1 $2 ; Mark the socket with the Rcon password. sockmark %sockname $3 } ; Catch all sockopens with the Source Rcon sockets prefix. ; Build the authentication request packet and send it to the server. on *:SOCKOPEN:$($+($srcon.prefix, *)): { ; Initialize the request ID for the connection. set %srcon.id. $+ $sockname 0 ; Constructed auth request to send to the server. srcon.getrequest &srcon.auth %srcon.id. [ $+ [ $sockname ] ] $srcon.req.auth $sock($sockname).mark ; Send the authentication packet. sockwrite $sockname &srcon.auth } ; Read data from the game server. on *:SOCKREAD:$($+($srcon.prefix, *)): { ; Get the window name for the current game server. var %srcon.window = $+(@, $remove($sockname, $srcon.prefix)) ; If there were errors, $sockerr will tell us so. ; Write the error message to the window and clear the connection. if ($sockerr) { aline 04 %srcon.window * Error: Reading from socket: $sock($sockname).wsmsg srcon.clear $sockname return } ; If a prior packet didn't finish receiving, continue reading it. if ($hget($sockname)) { ; Set the packet size. var %srcon.pckt.size = $hget($sockname, size) ; Set the number of bytes left to read. var %srcon.pckt.left = $hget($sockname, left) ; Set the request id. var %srcon.pckt.id = $hget($sockname, id) ; Set the command response type. var %srcon.pckt.cmd = $hget($sockname, cmd) ; Set the cut string1. noop $hget($sockname, string1, &srcon.pckt.string1) ; Read the rest of string1. sockread %srcon.pckt.left &srcon.pckt.rest dec %srcon.pckt.left $sockbr ; Append the rest of string1 to the already received string1. bcopy &srcon.pckt.string1 $calc($bvar(&srcon.pckt.string1, 0) + 1) &srcon.pckt.rest 1 -1 ; Clear the un-needed variables. hfree $sockname } ; Else, if the packet wasn't splitted. else { ; Read the packet size. sockread 4 &srcon.pckt.size var %srcon.pckt.size = $bvar(&srcon.pckt.size, 1).long ; Initialize the number of bytes left to read. var %srcon.pckt.left = %srcon.pckt.size ; Read the packet id. sockread 4 &srcon.pckt.id var %srcon.pckt.id = $bvar(&srcon.pckt.id, 1).long dec %srcon.pckt.left $sockbr ; If the request id is an error, stop processing, display an error and clear the connection. if ($srcon.inttobytes(%srcon.pckt.id) == 255 255 255 255) { aline 04 %srcon.window * Error: Failed authentication (probably wrong password). srcon.clear $sockname return } ; Read the packet command response type. sockread 4 &srcon.pckt.cmd var %srcon.pckt.cmd = $bvar(&srcon.pckt.cmd, 1).long dec %srcon.pckt.left $sockbr ; Read string1. sockread %srcon.pckt.left &srcon.pckt.string1 dec %srcon.pckt.left $sockbr } ; If the number of bytes left to read is still positive, the packet was splitted. ; This means that we'll save the variables to globals so it can be used in the next read. if (%srcon.pckt.left > 0) { hmake $sockname hadd $sockname size %srcon.pckt.size hadd $sockname left %srcon.pckt.left hadd $sockname id %srcon.pckt.id hadd $sockname cmd %srcon.pckt.cmd hadd -b $sockname string1 &srcon.pckt.string1 } ; Only if we've finished reading all the packet, display it. ; NOTE: At this point, string1 also contains string2 (the one 0x00 byte), however it doesn't matter to us ; since we're only reading the text which is terminated in string1 by a 0x00 byte. elseif (%srcon.pckt.left == 0) { ; If the response type was an auth response, display a "connected" message. if (%srcon.pckt.cmd == $srcon.res.auth) { aline 12 %srcon.window Now connected! } ; If the response type was a command response, display it. elseif (%srcon.pckt.cmd == $srcon.res.cmd) { ; Convert the binary string1 to a usable variable. var %srcon.pckt.string1 = $bvar(&srcon.pckt.string1, 1, $bvar(&srcon.pckt.string1, 0)).text ; Tokenize the lines to be printed and print them. tokenize $asc($lf) %srcon.pckt.string1 aline %srcon.window $* } } } ; Sockets may close on their own if not kept alive. ; In case that happens when the window is still open, the socket will be reopened. on *:SOCKCLOSE:$($+($srcon.prefix, *)): { ; Get the window name for the current game server. var %srcon.window = $+(@, $remove($sockname, $srcon.prefix)) ; If the window and the current request id still exists, reopen the socket. if (($window(%srcon.window)) && (%srcon.id. [ $+ [ $sockname ] ])) { ; Save the socket details before terminating it. %srcon.name = $sockname %srcon.ip = $sock($sockname).ip %srcon.port = $sock($sockname).port %srcon.pass = $sock($sockname).mark ; Terminate the socket so it could be reopened. sockclose $sockname ; Reopen the socket to the server. sockopen %srcon.name %srcon.ip %srcon.port ; Mark the socket with the Rcon password. sockmark %srcon.name %srcon.pass } } ; Sends user input to the server as is. ; NOTE: Commands like exit or quit will close the server! on *:INPUT:@: { ; Get the socket name. var %srcon.socket = $+($srcon.prefix, $remove($target, @)) ; If the input is not for the Source Rcon window, ignore it. if ($($+(%, srcon.id., %srcon.socket), 2) == $null) { return } ; Check if the socket is still alive. if (!$sock(%srcon.socket)) { aline 04 $target * Error: Socket is dead. Close the window and try again. return } ; Build the execute command request packet and send it to the server. ; Increment the current request id. inc %srcon.id. $+ %srcon.socket ; Construct the request to send to the game server. srcon.getrequest &srcon.cmd %srcon.id. [ $+ [ %srcon.socket ] ] $srcon.req.execcmd $1- aline $target -> $1- ; Send the command request. sockwrite %srcon.socket &srcon.cmd } ; If the user has closed the rcon window, clear the socket. on *:CLOSE:@: { srcon.clear $+($srcon.prefix, $remove($target, @)) } ; Constructs a request with the given parameters: ; $1 = Bvar to store the request ; $2 = Request ID ; $3 = Request type ; $4- = Request data (password/command) alias -l srcon.getrequest { ; Clear the given bvar to make sure it doesn't contain any preset values. bunset $1 ; Set the given request ID in the request. bset $1 5 $srcon.inttobytes($2) ; Set the given request type. bset $1 9 $srcon.inttobytes($3) ; Set string1 the request data. bset -t $1 13 $4- ; Terminate string1 with 0x00 and set string2 to 0x00. bset $1 $calc($bvar($1,0) + 1) 00 00 ; Set the packet size. bset $1 1 $srcon.inttobytes($calc($bvar($1, 0) - 4)) } ; Clears the socket and the request id. alias -l srcon.clear { ; If there's a socket named accordingly, close it. if ($sock($1)) { sockclose $1 } ; Clear the id var. unset %srcon.id. $+ $1 }