Help - Search - Members - Calendar
Full Version: Xpertmud
Achaea's Forums > Off-Topic > Tech Support > Client Help
kouts
Hello all, and particularly Wulfen biggrin.gif

I recently downloaded and compiled the xpertmud client and it is running very nicely so far, except one or two small problems:

First of all, I would like to know if there is a log support. I could trigger every line sent or received and write it to a file but if there is a way to do this from inside the client it would be nice.

One other thing is that after the prompt and in a few other places (login screen) I get some funny characters at the end of line <IAC><GA>

CODE
Published by my decree on the 24th of Mayan, in the year 432 AF.
3240h, 3168m, 15100e, 13300w ex-<IAC><GA>rn
You have no further news to read.
3240h, 3168m, 15100e, 13300w ex-<IAC><GA>qq
You grow still and begin to silently pray for preservation of your soul while
you are out of the land.
3240h, 3168m, 15100e, 13300w ex-<IAC><GA>


I have tried both triggers:
CODE
addTrigger("End_of_line","<IAC><GA>","")
addTrigger("End_of_line","<IAC><GA>","\n")


and the first one seems to behave better in terms of reducing spam, although echos from script are a bit messed up. I could take a look at the C++ code, but lets say that I don't wanna.

One last thing, since I have not had much experience yet, it seems that some triggers I tried do not work. For instance:
CODE
addTrigger("prompt_test", '\d+h\, \d+m\, \d+e\, \d+w .*' ,"sub{statusWindow()->show('prompt\n');return 1;}")

this doesn't seem to match any input. Any ideas?

<Disclaimer>
I haven't looked at perl for quite some time, so if something of the above is incredibly stupid please say so.
</Disclaimer>

Thanks in advance...

Edit: Sorry for the multiple posts, but I have problems with the forums lately. Could a moderator please delete the other (empty) threads?
Alyssandra
teh IAC GA are part of the telnet protocol GA is go ahead it is used to tell the client that it is ok to send data. Most MUDs use GA on their prompts for this reason. I would imagine there is a way to suppress it in xpertmud, but triggering wont help because its not the actual characters IAC GA you are getting its the byte 255 249
Trevize
QUOTE (kouts @ Oct 5 2006, 11:05 AM) *
Hello all, and particularly Wulfen biggrin.gif

I recently downloaded and compiled the xpertmud client and it is running very nicely so far, except one or two small problems:

First of all, I would like to know if there is a log support. I could trigger every line sent or received and write it to a file but if there is a way to do this from inside the client it would be nice.

One other thing is that after the prompt and in a few other places (login screen) I get some funny characters at the end of line <IAC><GA>

CODE
Published by my decree on the 24th of Mayan, in the year 432 AF.
3240h, 3168m, 15100e, 13300w ex-<IAC><GA>rn
You have no further news to read.
3240h, 3168m, 15100e, 13300w ex-<IAC><GA>qq
You grow still and begin to silently pray for preservation of your soul while
you are out of the land.
3240h, 3168m, 15100e, 13300w ex-<IAC><GA>


I have tried both triggers:
CODE
addTrigger("End_of_line","<IAC><GA>","")
addTrigger("End_of_line","<IAC><GA>","\n")


and the first one seems to behave better in terms of reducing spam, although echos from script are a bit messed up. I could take a look at the C++ code, but lets say that I don't wanna.

One last thing, since I have not had much experience yet, it seems that some triggers I tried do not work. For instance:
CODE
addTrigger("prompt_test", '\d+h\, \d+m\, \d+e\, \d+w .*' ,"sub{statusWindow()->show('prompt\n');return 1;}")

this doesn't seem to match any input. Any ideas?

<Disclaimer>
I haven't looked at perl for quite some time, so if something of the above is incredibly stupid please say so.
</Disclaimer>

Thanks in advance...

Log support, I don't believe it has, someone correct me if I'm wrong. But you can easily create code that writes every line to a file, as you found out.

IAC/GA has to do with terminating the prompt, the MUD sends it, I'd recommend the first, or changing it to a space, " "

Not sure about the triggers.

edit: Don't think the "" needs to be around sub{statusWindow()->show('prompt\n');return 1;}
Alyssandra
I am pretty sure Achaea has a config option to send newline with the prompts...that might solve your problem
kouts
In fact the trigger works. I know that these are not the characters that the MUD sends, but apparently xpertmud converts them to the sequence <IAC><GA> because it doesn't recognises them. But as I said the trigger that substitutes "<IAC><GA>" with "" creates problems with echos from scripts and the one that substitutes with "\n" creates spammy blank lines...
Trevize
QUOTE (Alyssandra @ Oct 5 2006, 11:15 AM) *
teh IAC GA are part of the telnet protocol GA is go ahead it is used to tell the client that it is ok to send data. Most MUDs use GA on their prompts for this reason. I would imagine there is a way to suppress it in xpertmud, but triggering wont help because its not the actual characters IAC GA you are getting its the byte 255 249

You should still be able to sub it out.

QUOTE (kouts @ Oct 5 2006, 11:21 AM) *
In fact the trigger works. I know that these are not the characters that the MUD sends, but apparently xpertmud converts them to the sequence <IAC><GA> because it doesn't recognises them. But as I said the trigger that substitutes "<IAC><GA>" with "" creates problems with echos from scripts and the one that substitutes with "\n" creates spammy blank lines...


One blank line after the prompt? That is what I get in zmud too, and most people do, I believe.
Alyssandra
QUOTE (Trevize @ Oct 5 2006, 04:21 PM) *
QUOTE (Alyssandra @ Oct 5 2006, 11:15 AM) *

teh IAC GA are part of the telnet protocol GA is go ahead it is used to tell the client that it is ok to send data. Most MUDs use GA on their prompts for this reason. I would imagine there is a way to suppress it in xpertmud, but triggering wont help because its not the actual characters IAC GA you are getting its the byte 255 249

You should still be able to sub it out.


Yes, but not as characters....though apparently you can in xpertmud. I misunderstood what he was saying in the first post.

I still think if you try config newline or whatever it is, you might find the problem goes away.
Trevize
QUOTE (Alyssandra @ Oct 5 2006, 11:23 AM) *
I still think if you try config newline or whatever it is, you might find the problem goes away.

I don't believe achaea has an option like that.

edit: Useless information, but if I recall, GA stands for 'go ahead'.
Alyssandra
QUOTE (Trevize @ Oct 5 2006, 04:24 PM) *
QUOTE (Alyssandra @ Oct 5 2006, 11:23 AM) *

I still think if you try config newline or whatever it is, you might find the problem goes away.

I don't believe achaea has an option like that.

edit: Useless information, but if I recall, GA stands for 'go ahead'.


Are you sure I thought it did, but maybe it was one of the other IRE muds.

And yes its Go Ahead, like I said in my first post tongue.gif and IAC is Is A Command
Trevize
QUOTE (Alyssandra @ Oct 5 2006, 11:29 AM) *
QUOTE (Trevize @ Oct 5 2006, 04:24 PM) *

QUOTE (Alyssandra @ Oct 5 2006, 11:23 AM) *

I still think if you try config newline or whatever it is, you might find the problem goes away.

I don't believe achaea has an option like that.

edit: Useless information, but if I recall, GA stands for 'go ahead'.


Are you sure I thought it did, but maybe it was one of the other IRE muds.

And yes its Go Ahead, like I said in my first post tongue.gif and IAC is Is A Command

I was posting when you posted yours, so I missed it. tongue.gif

I just checked, no such option.
Wulfen
First, big disclaimer: I'm not a professional. There are no doubt many better ways to code for Achaea than this one. Use any of my advice at your peril.

So...

There is no hardcoded log support, so you have to code your own (better) logging. While you can do this with triggers, you can also redefine $onTextReceived, $onTextEntered, and $onKeyPressed to cover more. I have logging code embedded right into my system, since calling a subroutine to send multiple commands to Achaea isn't covered by the usual "alias: command, replacement" syntax that addAlias offers.

To ensure that logging is available throughout my system, I start defining variables and pulling in modules in achaea-live.pl, the file called from my Achaea bookmark in Xpertmud, like so:

CODE
#addIncludeDir('/home/cw/achaea/system');
#parse('achaea-live.pl');


This file doesn't have any actual code, it just wraps everything up nice and snug:

CODE
###
### Main Achaea wrapper script
###

use strict;
use warnings;

use DBI;
use Data::Dumper;
use IO::File;
use File::Slurp;
use Time::HiRes qw(time);

use vars qw($linePart $winstatus $winmain $winprompt $wintracking $cwlogging $cwlogprefix $id %vtracking %settings);

# parse the various system files
parse("system-datastructures.pl");
parse("system-subroutines.pl");
parse("aliases-settings.pl");
parse("aliases-combat.pl");
parse("aliases-noncombat.pl");
parse("aliases-skills.pl");
parse("aliases-apostate.pl");
parse("triggers-combat.pl");
parse("triggers-event.pl");
parse("client-xpertmud.pl");

# ensure everything is loaded and ready go to
loadsettings();
loadeyes();
resettracking();
racechange($settings{race});
ton();
llp("Achaea system fully loaded.");


The file "client-xpertmud.pl" contains my redefinitions of Xpertmud internals, usually found in the Xpertmud source in xpertmud/scripting/perl/sysinit.pl. Previously I just modified that file and recompiled, but it's far better to define your own in your system, then you're not potentially recoding everytime Globbi comes out with a new Xpertmud.

I also have to do my own logging since I want things to go to my own windows, not just statusWindow(). You can also see the secret to how well I ignore illusions that lifevision catches - I simply don't pass known illusions to triggers.

Of course, use the file below as an example - it's not worth much without the rest of my system included. It may not nest correctly in the Achaea forums, but checking the page's html source may make things clearer.

CODE
###
### client settings pertaining to how I want xpertmud to run
###

# window definitions

$winstatus = statusWindow();
#$winstatus->minimize();
#$winmain->resizeChars(80, 24);
$winstatus->hide();

$winmain = new XMTextBufferWindow();
$winmain->move(0, 0);
$winmain->setTitle('Main');
$winmain->resizeChars(85, 32);
$winmain->setCursor(0,0);
$winmain->show();
$winmain->raise();

$winprompt = new XMTextWindow();
$winprompt->setTitle('Prompt');
$winprompt->resizeChars(56, 1);
$winprompt->move(0,498);
$winprompt->setCursor(0,0);
$winprompt->show();
$winprompt->raise();

$wintracking = new XMTextWindow();
$wintracking->setTitle('Tracking');
$wintracking->resizeChars(24, 36);
$wintracking->move(610,0);
$wintracking->setCursor(0,0);
$wintracking->show();
$wintracking->raise();

# setting up logging

# this should make it so that things don't echo to StatusWindow, I hope
$isEcho = 1;

# this is the connection number, since we only play Achaea it's always 0
$id = 0;

# I hate this
delAlias("LOCAL_ECHO");

{
    # setting up the logging filehandle object, using >> to append
    my $cwlogdir = '/home/cw/achaea/logs';

    # get the date string, via system date
    chomp(my $cwdate = `/bin/date +%F_%k-%M-%S`);

    # remove any ugly spaces
    $cwdate =~ s/ //g;

    # so this is where we log to
  my $cwfilename;
  if ($cwlogprefix) {
    $cwfilename = "${cwlogdir}/${cwlogprefix}${cwdate}.$$.log";
  } else {
    $cwfilename = "${cwlogdir}/${cwdate}.$$.log";
  }

    # and now we open the filehandle object
    $cwlogging = new IO::File ">> $cwfilename";
}

# --------------------------------------------------

# personalized onTextReceived sub

# temp for chunk testing
#chomp(my $cwdate = `/bin/date +%F_%k-%M-%S`);
#$cwdate =~ s/ //og;
#my $xlogging = new IO::File ">> /home/cw/achaea/logs/chunklog${cwdate}.log";
#my $xlogging = new IO::File ">> /home/cw/achaea/logs/timelog${cwdate}.log";

resetWriteRegExps();
$onTextReceived = sub {
  my $text=shift;
  my $id = shift;
  return undef if $text =~ /<IAC><GA>/o;

  # for achaea chunk testing
  #print $xlogging "\n------------------------------------------\n";
  #if ($text =~ /(\d+)h,.+ (\d+)m.+ ([ebdxkc]+)-$/oms) {
    #print $xlogging "CHUNK ENDS WITH PROMPT\n";
  #}
  #print $xlogging $text;


  if(ref $triggerPreprocessing eq "CODE") {
    $text = &$triggerPreprocessing($text);
  }

  #my $xtime = sprintf("%.5f",time);

  if (defined $text) {
    $text = $linePart . $text if $linePart;
    foreach my $line (split /(?<=\n)/, $text) {
      $linePart = "";
      if($line =~ s/\r?\n$/\n/o) {
        if(ref $onLineReceived eq "CODE") {
          $line = &$onLineReceived($line);
        }
        # don't use ^ here, as there may be ansi colouring
        $line = executeTriggers($line) unless $text =~ /\*\* Illusion \*\*/oms;
        #if(defined $line && ($line ne "" || $line !~ /^\r$/o)) {
        if(defined $line && $line ne "") {
          $winmain->print($line);
          # strip nasty ansi
          $line =~ s/\e[^m]*m//og;
          print $cwlogging $line;
          #print $xlogging "$xtime: $line";
        }

      } else {
        if(($line =~ /$writeAtOnceRegExp/) && ($line !~ /$dontWriteAtOnceRegExp/)) {

          # don't use ^ here, as there may be ansi colouring
          $line = executeTriggers($line) unless $text =~ /\*\* Illusion \*\*/oms;
          #if(defined $line && ($line ne "" || $line !~ /^\r$/o)) {
          if(defined $line && $line ne "") {
            $winmain->print($line);
            # strip nasty ansi
            $line =~ s/\e[^m]*m//og;
            print $cwlogging $line;
            #print $xlogging "$xtime: $line";
          }

        } else {
          $linePart = $line;
        }
      }
    }
  }
};

$onTextEntered = sub {
  my $text = shift;
  if(ref $aliasPreprocessing eq "CODE") {
    $text = &$aliasPreprocessing($text);
  }
  $text = executeAliases($text);
  if(defined $text) {
    $winmain->print("$text\n");
    print $cwlogging "$text\n";
    connection($id)->send("$text\n");
  }
};

$onKeyPressed = sub {
  my $key = shift;
  my $ascii = shift;
  if (ref $keyPreprocessing eq "CODE") {
    ( $key, $ascii ) = &$keyPreprocessing($key, $ascii);
  }
  if(defined $key) {
    if(executeKeyBindings($key)) {
      return 1;
    }
    if($isEcho) {
      return undef;
    } else {
      if ($key =~ /KP_Enter/ or $key =~ /Return/) {
        print $cwlogging "\n";
        connection($id)->send("\n");
      } elsif(defined $ascii && $ascii =~ /^.$/) {
        print $cwlogging "$ascii\n";
        connection($id)->send("$ascii\n");
      }

      sendKey($key, $ascii);
      return 1;
    }
  }
  return undef;
};

delKeyBinding(qr/^Scroll-/o);

addKeyBinding('Scroll-Up', '.000.... PgUp', sub {
  $winmain->scrollLines(-int($winmain->getLines()/2));
  return undef;
});
addKeyBinding('Scroll-Down', '.000.... PgDown', sub {
  $winmain->scrollLines(int($winmain->getLines()/2));
  return undef;
});


This stuff is straightforward as long as you're only typing and receiving text, or doing simple aliases. When I want to have a subroutine to do multiple things at once, I have to do things differently. I define lower level subroutines to handle sending/logging/displaying text, rather than call the xpertmud internals (the XM:: routines) right in my system. Here's an example, the standard lp (log and print to screen/Achaea) subroutine:

CODE
# one to log and lp every sent line
sub lp {
    my $text = "@_";
    $text =~ s/[\r\n]+$//o;
    print $cwlogging "$text\n";
    $winmain->print("$text\n");
    XM::send("$text\n");
    # not hyperventilating when I chain commands
    setalarm('holdbreath_sent', time);
    return undef;
}


That means that my simple versus complicated aliases tend to look like this:

CODE
addAlias("lep", qr/^lep$/o, "leprosy", 1);

addAlias("bw", qr/^bw$/o, sub {
  lp("stand");
  lp("config prompt hmw");
  lp("blackwind");
  return undef;
}, 1);


Note the return undef so that Xpertmud doesn't send any more text to Achaea than I want it to. In the first alias example, "leprosy" is the text returned from the alias, and is then sent to the world.

The <IAC><GA> is part of telnet, and I asked about a hardcoded solution, though nothing yet. I can't code C++, so I can't do anything about it myself. The sequence is always sent as its own chunk of data from Achaea, so you can ignore it by the line you've seen above in $onTextReceived:

CODE
return undef if $text =~ /<IAC><GA>/o;


You could also likely handle this through your prompt trigger, but this is the solution I chose for myself. If you want to see more about how Achaea sends data to you, some of my commented bits in $onTextReceived are what I once used to examine how Achaea sends text data.

One of my prompt triggers is as follows:

CODE
# everything and the kitchen sink winds up here
addTrigger("trig_promptfull", qr/^(.*[0-9]+h,.+[0-9]+m.+-) ?$/o, \&prompt, 1, 0);


You'll notice above how I strip ansi before I log incoming text, but after I check triggers, so I have to account for ansi colour in my triggers. Your regex likely isn't taking into account that there are ansi codes in the coloured prompt text you see. The ansi is what gives everything its colour, so you just have to work around it.

My only other trigger tip is to use the qr//o regex construct for pattern matching instead of "" quotes. The reason for the former is that with the o modifier the regex is only compiled once when your script is parsed, rather than every time your client checks the trigger in question. With many triggers, this can knock hundreds of milliseconds of processing time off your system's reactions when you're trying to get out of an axewhoring or similar tactic.
kouts
I officialy want to join your fan-club biggrin.gif Thank you. Very valuable information
Alyssandra
I just had a look through xpertmuds sourcecode, and it appears that the latest SVN version does strip the GA correctly. I will look in more depth over the weekend and see if I can give you a patch to fix the GA stripping.
kouts
Well, looking around at their forums (http://sourceforge.net/forum/?group_id=29649) I found this:

QUOTE
By: Ernst Bachmann - entropyProject Admin
RE: <IAC><GA> ?
2004-02-06 10:40
Thats kind of a feature...
Your Mud sends a "IAC Go Ahead" (telnet command) to indicate the client should print out the line, despite it being not complete. (used for prompts, etc)
xpertmud forwards that information to your script, so you can add Triggers for it (like parsing the prompt, etc)

Unfortunately the default (sysinit) script does not handle them right, so they're printed on screen.

Guess we should enhance the defaults scripts to handle those IACs, if the user-script doesn't explicitly want to receive them.


Therefore it's not a bug,so I'll probably handle it in the scrip. Thank you all for your help.
Keldar
If you can access the network packets (which it sounds like you can) then fixing that isn't difficult at all. This is a Lua function that I use for that purpose. It takes a packet and returns it with any modifications. The returned packet replaces the incoming one. Should be self-explanatory:

CODE
-- A boolean indicating whether the last prompt
-- in the previous packet was fixed
terminated = false


function OnPluginPacketReceived(packet)
    
    if PromptProcessor.fix then  -- fix prompts only if this option is set

      -- A Lua pattern for ANSI codes
      --
      local pat = "^(\27%[%d?;?%d%dm)\13\10(.*)"

      -- This checks if we've replaced GA at the end of the previous packet
      -- and whether this packet starts with a newline
      --
      if terminated and (string.sub(packet, 1,2) == "\13\10") then
    
        -- Remove the newline at the start of this packet, so we don't get a duplicate
        --
        packet = string.sub(packet, 3, -1)
        terminated = false

      -- If this packet doesn't start with a newline, but the previous was terminated
      -- and we have an ANSI code at the beginning of this one then
      --
      elseif terminated and string.find(packet,pat) then

        -- Check whether the ANSI code is followed by a newline and if yes -
        -- remove that newline (see the ANSI code pattern above)
        --
        packet = string.gsub(packet, pat, "%1%2")
        terminated = false
      end

      -- Here we just replace all GA codes in a packet with newlines, taking care
      -- to not create any duplicate newlines
      --
      if string.find(packet, "\255\249") then
        packet = string.gsub(packet, "\255\249\13\10", "\13\10")
        packet = string.gsub(packet, "\255\249", "\13\10")
        terminated = true
      else
        terminated = false
      end
    end

     -- And return the fixed packet    
    return packet
end


This should work in at least 99% of all cases, barring freak accidents that aren't really worth caring about.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2009 Invision Power Services, Inc.