Sign in to follow this  
Followers 0
Obi-w00t

Building Ordered Trees Hierarchies From Arrays

4 posts in this topic

Hi there, I am using AutoIt to create reports on Teamspeak servers (Teamspeak is a voice chat software) on who is online and in which room they are in. So far I have got the script to tell me who is online and which room they are in but I now have another problem with hierarchy. Some of the channels are sub-channels - meaning they are linked to other channels. This image may explain things.

What I need to do is sort the output so that these children and parents are in their correct order i.e. the children after the parent.

Below are the sample outputs of connecting to a Teamspeak server and querying for user data and channel data:

Player List:

p_id    c_id    ps  bs  pr  br  pl  ping    logintime   idletime    cprivs  pprivs  pflags  ip  nick    loginname
1   2   40396   1418136 1901    571542  1622    22  41720   6   1   5   0   "0.0.0.0"   "Ben"   "Murdock"   
7   2   21718   4671816 11080   3588037 23  17  8949    13  1   5   0   "0.0.0.0"   "HockeyNut" "Hockeynut" 
10  9   9172    819555  1073    336039  28  116 7659    185 0   5   0   "0.0.0.0"   "barney"    "bust"  
11  2   15601   3723574 3888    1254313 10  85  5089    2   0   5   0   "0.0.0.0"   "Irish" "irish" 
12  2   14771   3532423 3281    1060128 9   58  4807    10  0   5   0   "0.0.0.0"   "sam"   "sam"
OK

Channel List:

id  codec   parent  order   maxusers    name    flags   password    topic
1   12  -1  0   70  "Checkpoint Charlie"    16  0   "KwK - Teamspeak"
2   12  -1  3210    64  "Battlefield 2" 8   0   ""
3   12  -1  3230    30  "Just Race!"    8   0   "für die Helden der Rennbahn"
4   8   -1  3240    30  "World of Warcraft" 8   0   "für Elfen und Orks..."
5   8   -1  3220    30  "Counterstrike" 8   0   "back to the roots..."
6   6   -1  3270    30  "ZZZ AFK ZZZ"   8   0   ""
7   10  -1  3235    51711   "Sleeper`s Wohnzimmer"  8   0   "Das Heim der Götter"
8   10  -1  3200    70  "Company of Heroes" 0   0   ""
9   9   -1  3231    10  "Tiger-one´s Kübelwagen Garage"   0   0   "Tiefer Härter Breiter!!! Passat Variant second Edition!"
10  10  -1  3231    70  "Stocki `s Sex-Shop"    0   0   "Taschenmuschis zu verkaufen!"
11  10  -1  3200    10  "America's Army"    0   0   "Wir lieben Bush!!!!"
12  10  -1  3200    4   "Supreme Commander" 10  0   "Buh"
13  10  -1  3200    70  "Topo's Modellbahntreff"    0   0   ""
14  5   -1  3800    70  "Es rauscht!!!!!"   0   0   ""
15  5   -1  3200    70  "Silent Hunter" 8   0   ""
16  12  2   3211    32  "Squad Schreihals"  0   0   ""
17  12  2   3212    32  "Squad Hasenfuss"   0   0   ""
18  8   4   3200    45  "Hex Hex"   0   0   "nur für Stocki..."
19  5   15  3200    70  "SH III"    0   0   ""
20  5   15  3200    70  "SH IV" 0   0   ""
OK

On the channel list all the "parents" of the tree are -1 and those that are not have the value of their parent in that column. Below is all the code I have so far:

$szIPAddress = InputBox("IP Address",@LF & @LF & "Enter IP address of server:")
$szTSPort = InputBox("TS Port",@LF & @LF & "Enter the port of the Teamspeak server:")

$nPORT = "51234"

$sEnd = "Server @ " & $szIPAddress & ":" & $szTSPort & @CRLF

; Start The TCP Services
;==============================================
TCPStartUp()

; Initialize a variable to represent a connection
;==============================================
Dim $ConnectedSocket = -1

;Attempt to connect to SERVER at its IP and PORT 33891
;=======================================================
Do
$ConnectedSocket = TCPConnect($szIPAddress,$nPORT)
Until $ConnectedSocket <> -1

MsgBox(0,"","Connected")

Dim $szData

$level = 0

While $level <5
    Do
        $recv = TCPRecv( $ConnectedSocket, 2048 )
    Until $recv <> ""
    
    ;Find out which stage of transmission we are on
    Select
        ;List server ports (not strictly required)
        Case $level = 0
            $szData = "sl"
            $level = 1
        ;Select the server port we want
        Case $level = 1
            $szData = "sel " & $szTSPort
            $level = 2
        ;List users (file gets dumped on next level)
        Case $level = 2
            $szData = "pl"
            $level = 3  
        ;List channels (file gets dumped on next level)
        Case $level = 3
            $szData = "cl"
            FileWrite("pl.log", $recv)
            $plarray = DecodePL()
            FileDelete("pl.log")
            $level = 4  
        ;Get some server info (not strictly required)
        Case $level = 4
            $szData = "si"
            FileWrite("cl.log", $recv)
            $clarray = DecodeCL()
            ;FileDelete("cl.log")
            $level = 5
    EndSelect
    ;Send what we just set
    TCPSend($ConnectedSocket,$szData & @CRLF)
WEnd

For $n = 0 to UBound($clarray) - 1
    ;MsgBox(0,"Channel", "Name: " & $clarray[$n][0] & " | " & "ID: " & $clarray[$n][1])
    $sEnd &= "[]: " & $clarray[$n][0] & @CRLF ; & "ID: " & $clarray[$n][1] & @CRLF
    For $i = 0 to UBound($plarray) - 1
        ;If $plarray[$i][1] = $clarray[$n][1] Then MsgBox(0,"User", "Name: " & $plarray[$i][0] & " | " & "In Channel: " & $clarray[$n][0])
        If $plarray[$i][1] = $clarray[$n][1] Then $sEnd &= "   -=" & $plarray[$i][0] & @CRLF ; & "In Channel: " & $clarray[$n][0] & @CRLF
    Next
Next

MsgBox(0,"End Result",$sEnd)

TCPCloseSocket($ConnectedSocket)

TCPShutDown()

;These functions decode the text files, first the channel list
Func DecodeCL()
Local $iRows
Local $iVar
Local $array[1][2]
$lfile = FileOpen("cl.log", 0)
$vClipboardData = FileReadLine($lfile)
Do
    $vClipboardData = FileReadLine($lfile)
    $vElement=stringsplit($vClipboardData, @TAB)
    $iRows = $vElement[0]
    If $iRows < 9 Then ExitLoop
    If $iVar >= UBound($array,1) Then ReDim $array[$iVar+1][2] ;Resize to fit
    $array[$iVar][0] = $vElement[$iRows-3] ;Name to array
    $array[$iVar][1] = $vElement[1]        ;ID to array
    $iVar += 1
Until @error Or $vClipboardData = "OK" & @CRLF
FileClose($lfile)
Return $array
EndFunc

;Then decode the player list
Func DecodePL()
Local $iRows
Local $iVar
Local $array[1][2]
$lfile = FileOpen("pl.log", 0)
$vClipboardData = FileReadLine($lfile)
Do
    $vClipboardData = FileReadLine($lfile)
    $vElement=stringsplit($vClipboardData, @TAB)
    $iRows = $vElement[0]
    If $iRows < 16 Then ExitLoop
    If $iVar >= UBound($array,1) Then ReDim $array[$iVar+1][2] ;Resize to fit
    $array[$iVar][0] = $vElement[$iRows-2] ;Name to array
    $array[$iVar][1] = $vElement[2]        ;ID to array
    $iVar += 1
Until @error Or $vClipboardData = "OK" & @CRLF
FileClose($lfile)
Return $array
EndFunc

I know the code is kind of scrappy at times but I will clean it up once I have this issue sorted out.

If anyone can think of a way of sorting the data so it can be in the correct order in the tree could they please give me some advice on how to achieve this, thank you.

Share this post


Link to post
Share on other sites



Only 4 views :shocked:

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Open AutoIt helpfile and go to GUICtrlCreateTreeView() and GUICtrlCreateTreeViewItem().

There is also nice example how to make treeview items.

Edited by Zedna

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Open AutoIt helpfile and go to GUICtrlCreateTreeView() and GUICtrlCreateTreeViewItem().

There is also nice example how to make treeview items.

OK, I did want to just display the tree in text so it could be rendered on a webpage easily but this will have to do. Thanks anyway.

Edit: I found my own solution on how to do it with text only, thanks for the help anyway, Zedna. If anyone is interested in the code just PM me.

Edited by Obi-w00t

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0