Author Topic: Eggdrop -> soldat admin -> REFRESH :/  (Read 4966 times)

0 Members and 3 Guests are viewing this topic.

Offline Hydro

  • Major(1)
  • Posts: 31
Eggdrop -> soldat admin -> REFRESH :/
« on: September 23, 2007, 11:40:45 pm »
Hello, I have got eggdrop script to admining my soldat server:
Code: [Select]
set server_host localhost
set server_cmd_port 23073


bind pub - !con server_connect
bind pub - !dc server_disconnect
bind pub - !send server_send

proc read_server_sock {ssock schan} {
   set each_line [gets $ssock]

   putserv "PRIVMSG $schan :$each_line"
}

proc server_connect {nick uhost hand chan arg} {
   global server_host server_cmd_port server_sock

   set server_sock [socket $server_host $server_cmd_port]

   fileevent $server_sock readable [list read_server_sock $server_sock $chan]

   fconfigure $server_sock -buffering line
}

proc server_disconnect {nick uhost hand chan arg} {
   global server_sock

   close $server_sock

   putquick "PRIVMSG $chan :disconnected from the server..."
}

proc server_send {nick uhost hand chan arg} {
   global server_sock

   if {$arg != ""} {
      puts $server_sock $arg
      flush $server_sock
   }
}
But I can't make REFRESH, when I write on IRC:

On server there are 2 Dankos and 2 Snipers.
How to do it?

Offline FliesLikeABrick

  • Administrator
  • Flamebow Warrior
  • *****
  • Posts: 6144
    • Ultimate 13 Soldat
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #1 on: September 23, 2007, 11:47:38 pm »
If you look in this thread: http://forums.soldat.pl/index.php?topic=237.0

You will see that REFRESH is not sent back as ASCII data.  It is packed binary data that must be unpacked before it can be of any use to you.  That thread links to various threads and code pieces that should greatly aid you in doing so.

Offline Hydro

  • Major(1)
  • Posts: 31
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #2 on: September 24, 2007, 12:14:04 am »
I tried to join my script and ramirez's but it didn't work. I'll try after school.
Code: [Select]
bind pub - !con server_connect
bind pub - !dc server_disconnect
bind pub - !send server_send
bind pub - !info send_info

proc read_server_sock {ssock schan} {
   set each_line [gets $ssock]

   putserv "PRIVMSG $schan :$each_line"
}

proc server_connect {nick uhost hand chan arg} {
   global server_host server_cmd_port server_sock

   set server_sock [socket $server_host $server_cmd_port]

   fileevent $server_sock readable [list read_server_sock $server_sock $chan]

   fconfigure $server_sock -buffering line
utimer 1 ref
}

proc server_disconnect {nick uhost hand chan arg} {
   global server_sock

   close $server_sock

   putquick "PRIVMSG $chan :disconnected from the server..."
}

proc server_send {nick uhost hand chan arg} {
   global server_sock
   array set info [Soldat:ParseRefresh $server_sock]
   if {$arg != ""} {
      puts $server_sock $arg
      flush $server_sock
   }
}

proc send_info {nick uhost hand chan arg} {
global info
putquick "PRIVMSG $chan :gamemode : $info(gamemode) tlimit: $info(timelimit)"
}

proc ref {} {
   global server_sock
global info
   array set info [Soldat:ParseRefresh $server_sock]
utimer 1 ref
}

putlog "soldat-admin.tcl ver 0.1 by tomekk loaded"

proc Soldat:ParseRefresh packet {
if { [string length $packet] != 1188 } {
return
}

binary scan $packet "@800c32s32s32c32c32I32s4ca16iisc" teams kills deaths pings numbers ips scores map_len map timelimit timeleft limit gamemode

set players {}
set specs {}

for { set i 0 } { $i < 32 } { incr i } {
set team [lindex $teams $i]
if {$team != -1} {
binary scan $packet "@[expr $i*25]ca24" name_len name
set ip [lindex $ips $i]
set ip [join [list [expr ($ip >> 24) & 0xFF] [expr ($ip >> 16) & 0xFF] [expr ($ip >> 8) & 0xFF] [expr $ip & 0xFF]] .]

array set player [list id      [expr [lindex $numbers $i] & 0xFF] \
list name    [string range $name 0 [expr $name_len-1]] \
list team    $team \
list kills   [expr [lindex $kills $i] & 0xFFFF] \
list deaths  [expr [lindex $deaths $i] & 0xFFFF] \
list ping    [expr [lindex $pings $i] & 0xFF] \
list ip      $ip]

if {$team < 5} {
lappend players [array get player]
} else {
lappend specs [array get player]
}
}
}

for { set i 0 } { $i < 4 } { incr i } {
set scores [lreplace $scores $i $i [expr [lindex $scores $i] & 0xFFFF]]
}

array set info [list gamemode    $gamemode \
list num_players [llength $players] \
list num_specs   [llength $specs] \
list map         [string range $map 0 [expr $map_len-1]] \
list scores      $scores \
list limit       $limit \
list timelimit   [expr $timelimit / 3600] \
list timeleft    [expr $timeleft / 60] \
list players     $players \
list specs       $specs]

return [array get info]
}
« Last Edit: September 24, 2007, 12:19:07 am by Hydro »

Offline ramirez

  • Retired Soldat Developer
  • Camper
  • ******
  • Posts: 394
    • Soldat Central
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #3 on: September 24, 2007, 09:37:09 am »
You aren't supposed to pass the socket to the proc. First read the refresh packet to a variable (1188 bytes), after that pass that variable to the proc.

Offline Hydro

  • Major(1)
  • Posts: 31
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #4 on: September 24, 2007, 01:11:02 pm »
I wrote this code to check length this variable:
Code: [Select]
bind pub - !con server_connect
bind pub - !dc server_disconnect
bind pub - !send server_send
bind pub - !info send_info
set server_host localhost
set server_cmd_port 23073
set i 0

proc read_server_sock {ssock schan} {
global i   
set each_line [gets $ssock]

   putserv "PRIVMSG $schan :$each_line"
if {$i == 2} {
set refresh $each_line
set i 0
putserv "PRIVMSG #zomfgpl : Length of variable [string length $refresh]"

}
if {$i == 1} {
set i [expr $i + 1]
}

}

proc server_connect {nick uhost hand chan arg} {
   global server_host server_cmd_port server_sock

   set server_sock [socket $server_host $server_cmd_port]

   fileevent $server_sock readable [list read_server_sock $server_sock $chan]

   fconfigure $server_sock -buffering line
utimer 1 ref
}

proc server_disconnect {nick uhost hand chan arg} {
   global server_sock

   close $server_sock

   putquick "PRIVMSG $chan :disconnected from the server..."
}

proc server_send {nick uhost hand chan arg} {
   global server_sock
global i   

   if {$arg != ""} {
      puts $server_sock $arg
      flush $server_sock
   }
   if {$arg == "REFRESH"} {
set i [expr $i + 1] 
}
}

proc send_info {nick uhost hand chan arg} {
global info
putquick "PRIVMSG $chan :gamemode : $info(gamemode) tlimit: $info(timelimit)"
}

proc ref {} {
   global server_sock
global info
   
utimer 1 ref
}

putlog "soldat-admin.tcl ver 0.1 by tomekk loaded"

proc Soldat:ParseRefresh packet {
if { [string length $packet] != 1188 } {
putquick "PRIVMSG #zomfgpl : Length of variable: [string length $packet]"
return
}

binary scan $packet "@800c32s32s32c32c32I32s4ca16iisc" teams kills deaths pings numbers ips scores map_len map timelimit timeleft limit gamemode

set players {}
set specs {}

for { set i 0 } { $i < 32 } { incr i } {
set team [lindex $teams $i]
if {$team != -1} {
binary scan $packet "@[expr $i*25]ca24" name_len name
set ip [lindex $ips $i]
set ip [join [list [expr ($ip >> 24) & 0xFF] [expr ($ip >> 16) & 0xFF] [expr ($ip >> 8) & 0xFF] [expr $ip & 0xFF]] .]

array set player [list id      [expr [lindex $numbers $i] & 0xFF] \
list name    [string range $name 0 [expr $name_len-1]] \
list team    $team \
list kills   [expr [lindex $kills $i] & 0xFFFF] \
list deaths  [expr [lindex $deaths $i] & 0xFFFF] \
list ping    [expr [lindex $pings $i] & 0xFF] \
list ip      $ip]

if {$team < 5} {
lappend players [array get player]
} else {
lappend specs [array get player]
}
}
}

for { set i 0 } { $i < 4 } { incr i } {
set scores [lreplace $scores $i $i [expr [lindex $scores $i] & 0xFFFF]]
}

array set info [list gamemode    $gamemode \
list num_players [llength $players] \
list num_specs   [llength $specs] \
list map         [string range $map 0 [expr $map_len-1]] \
list scores      $scores \
list limit       $limit \
list timelimit   [expr $timelimit / 3600] \
list timeleft    [expr $timeleft / 60] \
list players     $players \
list specs       $specs]

return [array get info]
}
$i from 0 to 1 when write !send REFRESH
$i from 1 to 2 when send from server REFRESH
And:

Offline urraka

  • Soldat Developer
  • Flagrunner
  • ******
  • Posts: 703
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #5 on: September 26, 2007, 05:53:53 pm »
This thread came handy. I've been dealing with the admin connection also, and I can't make it work alright. I must be doing something wrong, since I've never used sockets or network streams. I'm using C#, and I have something like this:

Code: [Select]
try
{
// I get here with the connection entablished and the password sent already

// Writer is a StreamWriter and Reader is a StreamReader. Both conencted to the NetworkSocket

// At the beggining send a refresh command to get the players list.
Writer.WriteLine("REFRESH");
Writer.Flush();

while (true)
{
string text = Reader.ReadLine();

if (text.StartsWith("/perrochat "))
continue;

bool NickMatches = false;

// Check if it's a player saying something.
if (text[0] == '[')
{
foreach (string nick in Players.Values)
{
if (text.StartsWith("[" + nick + "]"))
{
NickMatches = true;
break;
}
}
}

if (NickMatches)
{
server.SendToAll("M" + text, this);
}
else if (text == "REFRESH")
{
GetPlayers(); // This will read the next 1188 bytes and parse some data
}
else if (text.IndexOf(" has joined the game.") >= 0 ||
text.IndexOf(" has left the game.") >= 0)
{
// Player list might have changed so update it.

Writer.WriteLine("REFRESH");
Writer.Flush();
}
else if ((DateTime.Now.Ticks - LastRefresh) / TimeSpan.TicksPerSecond >= 10)
{
Writer.WriteLine("REFRESH");
Writer.Flush();
}
}
}
catch
{...}

So, the data is parsed alright the first time in the GetPlayers method. But in the followings REFRESHes it's not. It doesn't even get a 1188 packet. I tried to debug it to see what was going on but didn't find much, but it seemed like the packet wasn't sent right after i read the "REFRRESH" line. Any ideas of what I'm doing wrong here? I read lines... if the line is REFRESH then read the 1188 length packet with this inside the GetPlayers method:

Code: [Select]
byte[] packet = new byte[1188];
int r = Tcp.GetStream().Read(packet, 0, 1188);

// .. then I parse the data. r should be 1188 but it's not always 1188 -_-

Any help appreciated :)
urraka

Offline ramirez

  • Retired Soldat Developer
  • Camper
  • ******
  • Posts: 394
    • Soldat Central
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #6 on: September 30, 2007, 08:36:27 am »
I've had the exact same problem with C#, and I don't really know why it doesn't get all of the 1188 bytes. I've posted about it on various C# forums as well, and nobody knows the cause. I think it might even be a bug in the TCP sockets of C# 2.0. I'm going to try the same thing in C# 3.0 and see if it still occurs.

Offline Hydro

  • Major(1)
  • Posts: 31
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #7 on: September 30, 2007, 11:48:00 pm »
I tried [string range $refresh 1188] and [string trim $refresh] but still doesn't work ;s

Offline ramirez

  • Retired Soldat Developer
  • Camper
  • ******
  • Posts: 394
    • Soldat Central
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #8 on: October 01, 2007, 01:27:23 pm »
Here's what you need to do... You first send REFRESH to the socket.. You then read the socket with gets function while you get REFRESH from the socket. When you get REFRESH, you can read it with:
Code: [Select]
fconfigure $sock -translation binary
set refresh [read $sock 1188]
After that you use Soldat:ParseRefresh to parse the refresh packet you got in $refresh

Offline urraka

  • Soldat Developer
  • Flagrunner
  • ******
  • Posts: 703
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #9 on: October 01, 2007, 02:01:55 pm »
I found why it wasn't working on C#. The StreamReader object has an internal buffer, so it reads more than a line when you call reader.ReadLine(). As I was using the NetworkStream -which I get from tcpClient.GetStream()- to read the binary data, it happened that part of that data was already read and buffered by the StreamReader when I called tcpClient.GetStream().Read(packet, 0, 1188). I solved it using the same StreamReader object to read the binary data, so I had to make a char[1188] and then convert it to byte[1188] with Encoding.ASCII.GetBytes().
urraka

Offline chrisgbk

  • Inactive Staff
  • Veteran
  • *****
  • Posts: 1739
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #10 on: October 01, 2007, 03:06:12 pm »
Also see the usage notes on the function on MSDN(emphasis mine):
Quote
This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.

This means you have to do something like:
Code: [Select]
byte[] packet = new byte[1188];
int BytesRead = 0;
while (BytesRead < 1188) {
  BytesRead += Stream.Read(packet, BytesRead, 1188 - BytesRead);
}

or:
Code: [Select]
byte[] packet = new byte[1188];
while (Stream.Available < 1188) {
  // loop
}
Stream.Read(packet, 0, 1188);

Just something to be aware of, if you happen to read data too quickly, which is probably only going to happen if you are on a slow connection, ie: dialup.

Offline Hydro

  • Major(1)
  • Posts: 31
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #11 on: October 01, 2007, 03:18:48 pm »
Hm, i don't know how to do it yet. I'll try tomorrow.

Offline ramirez

  • Retired Soldat Developer
  • Camper
  • ******
  • Posts: 394
    • Soldat Central
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #12 on: October 01, 2007, 03:40:28 pm »
That makes sense, and also explains why I was getting the correct amount of bytes with ReadLine() of StreamReader. Thanks for the heads up!

Offline tomekk

  • Major(1)
  • Posts: 1
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #13 on: October 08, 2007, 09:31:25 am »
hello,

Hydro :P

I wrote this very simple script for you on another egggdrop forum (polish forum).
I don't see any copyrights info or any link to orginal source. (check orginal source for reason)

link to 1st (or no:P) topic about this script:
http://eggdrop.takeda.tk/viewtopic.php?t=410

have fun,
best regards,
tomekk

P.S
please respect copyrights
« Last Edit: October 08, 2007, 01:27:39 pm by tomekk »
scripts at eggdrop.org and on my hdd :P

and more thing...
I never played soldat ;-]

Offline Quantifier

  • Major
  • *
  • Posts: 70
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #14 on: October 10, 2007, 03:51:22 pm »
This ParseRefresh proc looks broken. Why are there multiple 'list' arguments to 'list' command? and also, you might want to brace expr arguments.

array set player [list id [expr {[lindex $numbers $i] & 0xFF}] \
list name    [string range $name 0 [expr {$name_len-1}]] \
list team    $team \
list kills   [expr {[lindex $kills $i] & 0xFFFF}] \
list deaths  [expr {[lindex $deaths $i] & 0xFFFF}] \
list ping    [expr {[lindex $pings $i] & 0xFF}] \
list ip      $ip]


The same with second [array set]:

array set info [list gamemode    $gamemode \
list num_players [llength $players] \
list num_specs   [llength $specs] \
list map         [string range $map 0 [expr {$map_len-1}]] \
list scores      $scores \
list limit       $limit \
list timelimit   [expr {$timelimit / 3600}] \
list timeleft    [expr {$timeleft / 60}] \
list players     $players \
list specs       $specs]

Offline chrisgbk

  • Inactive Staff
  • Veteran
  • *****
  • Posts: 1739
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #15 on: October 11, 2007, 03:48:04 pm »
This ParseRefresh proc looks broken. Why are there multiple 'list' arguments to 'list' command? and also, you might want to brace expr arguments.

array set player [list id [expr {[lindex $numbers $i] & 0xFF}] \
list name [string range $name 0 [expr {$name_len-1}]] \
list team $team \
list kills [expr {[lindex $kills $i] & 0xFFFF}] \
list deaths [expr {[lindex $deaths $i] & 0xFFFF}] \
list ping [expr {[lindex $pings $i] & 0xFF}] \
list ip $ip]


The same with second [array set]:

array set info [list gamemode $gamemode \
list num_players [llength $players] \
list num_specs [llength $specs] \
list map [string range $map 0 [expr {$map_len-1}]] \
list scores $scores \
list limit $limit \
list timelimit [expr {$timelimit / 3600}] \
list timeleft [expr {$timeleft / 60}] \
list players $players \
list specs $specs]


That's because it was copy pasted from here: http://forums.soldat.pl/index.php?topic=212.msg126864#msg126864

and you had originally corrected that post here: http://forums.soldat.pl/index.php?topic=212.msg152443#msg152443

almost 6 months ago, but the original post was never edited to include your fixes.

Offline ramirez

  • Retired Soldat Developer
  • Camper
  • ******
  • Posts: 394
    • Soldat Central
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #16 on: October 12, 2007, 08:27:05 am »
The original post never did it that way, this guy must've edited it himself (I didn't look at the code so closely because I expected it's exact same as mine). I used many "array set"s before, as you can see from the post chrisgbk linked. I did it the way you suggested though, as you can see from the next post.

Offline Quantifier

  • Major
  • *
  • Posts: 70
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #17 on: October 12, 2007, 10:01:19 am »
The original post never did it that way, this guy must've edited it himself (I didn't look at the code so closely because I expected it's exact same as mine). I used many "array set"s before, as you can see from the post chrisgbk linked. I did it the way you suggested though, as you can see from the next post.

Originally you used lots of array sets:
array set array_name [list key value]
array set array_name [list key value]
array set array_name [list key value]
...

I suggested using single command:
array set array_name [list key value key value key value ... ]

But apparently you edited your original post to:
array set array_name [list key value list key value ... ]
Back then I didn't look at it closely either, but it's not the exact same, and has no chance to run properly.

Offline ramirez

  • Retired Soldat Developer
  • Camper
  • ******
  • Posts: 394
    • Soldat Central
Re: Eggdrop -> soldat admin -> REFRESH :/
« Reply #18 on: October 12, 2007, 11:17:38 am »
The original post never did it that way, this guy must've edited it himself (I didn't look at the code so closely because I expected it's exact same as mine). I used many "array set"s before, as you can see from the post chrisgbk linked. I did it the way you suggested though, as you can see from the next post.

Originally you used lots of array sets:
array set array_name [list key value]
array set array_name [list key value]
array set array_name [list key value]
...

I suggested using single command:
array set array_name [list key value key value key value ... ]

But apparently you edited your original post to:
array set array_name [list key value list key value ... ]
Back then I didn't look at it closely either, but it's not the exact same, and has no chance to run properly.
Ah I see what you mean now. Edited it in the original post.