[Crossfire-wiki] [Crossfire DokuWiki] page added: client_side_scripting:client_scripting_interface-basic_howto

no-reply_wiki at metalforge.org no-reply_wiki at metalforge.org
Thu Aug 17 20:15:42 CDT 2006


A page in your DokuWiki was added or changed. Here are the details:



Date        : 2006/08/17 20:15

User        : eracc

Edit Summary: created



==== Client Scripting Interface - Basic howto ====



=== Purpose of this manual ===

This Howto covers the scripting interface present in gtk and x11 client un
der linux and Windows (see notes at end).



=== What is the Client Scripting Interface? ===

Basically, the Client Scripting Interface is a way to have an external pro
gram (the script) interact client-side with your in-game behaviour. The sc
ript can have a copy of messages sent from the server to your client (ther
e is a wide variety of such messages), can have a copy of messages sent fr
om your client to the server (there are also lots of them), may request in
formation (on a item, a map square ...) and finally can issue commands to 
the server. Lets call those actions, respectively, server-client spying, c
lient-server spying, examining and interacting.



=== Pipes, stdout, stdin ===

	If this section causes you to consider puking by the second line, jump 
to the next section.



The script is a program which is external to the client. It can be written
 in a wide range of languages. This can be C, Java, Perl, Python, Bash scr
ipt, php, anything you can think about. How can this be possible? Let's ta
ke a look at what happens when you type "echo hello world" on a shell prom
pt. Sure it writes on your terminal "hello world". And if you are in a gra
phical shell prompt? It appears in the graphical console! Some process cha
nged your request of writing to screen to a complex process of //get some 
system font// and //render the line in the specified window at the specifi
ed position//. All this because when you ask to "write hello world to scre
en" you ask, really, to "write hello world to the standard output device".
 This standard output device is called stdout. There is also the stdin, wh
ich most of the time is your keyboard and stderr, the standard error devic
e being most of the time the same as stdout.\\  

\\ 

Ok, and now? Now what we use is exactly the same trick as the graphical co
nsole. when the client runs a script, it changes the script's stdin and re
place the keyboard input with it's own orders (using a pipe). And it chang
es the stdout so instead of writing to screen, the script sends data to th
e client (using another pipe). And this is how any language can be used. B
ecause every language can write to the screen and read from the keyboard!



=== First Script ===



Learn to say hello



Here we go for the first script. We will do quite simple things. We will a
sk our character to say "hello world" around. The script will be written i
n C because we simply need to choose a language. The script is quite simpl
e:



  int main(){

       printf("issue 1 1 say hello world\n");

  }





Name it first.c, compile it and launch it in your command shell:



  tchize at Urd:~$ /home/tchize/script/first



issue 1 1 say hello world



No surprise in the output (notice the \n at the end in source file). Now w
e are going to run it in the client. Start the client and log in your pref
ered server. When it's done, type in the following command:



  scripts



Client will say you have no running scripts. That's good. Now type:



  script <path_to_my_first_script>



where path_to_my_first_script is the location of your first script. For ex
ample I typed:



  script /home/tchize/script/first



and you character says hello to the world. Nice, isn't it? Now try this yo
urself with the following script:



  int main(){

       printf("issue 1 1 shout hello world!\n");

       printf("issue 1 1 shout I use scripts!\n");

  }



Do you get the idea? every printf you make is a command to the client scri
pting interface. So now let's look at this command. It begins with issue f
ollowed by 2 integers. The command __issue__ is part of the interacting of
 the Client Scripting Interface. It allows a script to send any command th
e player could send. There are lots of them i won't explain here. Just iss
ue the command 'help commands' to get the list. What are those 2 integers?
 The first one is repeat. It typically is used for dropping items, but can
 be used in other cases. The second integer, 1 or 0, is must send. If it i
s //one//, the command must be sent, if it is //zero//, command may be los
t in the client-server process. Most user will set this to 1.



=== Second Script ===



Spy Kids



What to do next? As you can see, our script doesn't wait very long after i
ssuing commands. And it doesn't get information from the client at all. In
 fact it just //hopes// it is really speaking to the client. We are going 
to write a simple script which will __issue__ a command to the client and 
then gets the result. We are going to spy!\\ 

\\ 

Use the following script and run it in client. Ensure you ran the client i
n a console or you won't see any result!



  #include <stdio.h>

  

  int main (){

        char buf[200];

        int len;

        printf ("monitor\n");

        fflush (stdout);

        for(;;){               

                len=read(0,buf,200);

                if(len)

                        write(2,buf,len);               

                else

                        exit(-1);

        }

  }



Now move a bit in the game. A few steps are enough! Look at your console, 
you should see something like this:



  monitor 0 0 east

  

  monitor 0 0 east

  

  monitor 0 0 east

  

  monitor -1 0 run 7

  

  monitor -1 1 run_stop



If you type the command __scripts__ in your client you will see our script
 is still running.\\ 

\\ 

Let's look more closely at the code. We define a character buffer and a le
ngth. We will use the buffer to read what the client sends to the script. 
Then our script sends to the client the command __monitor__ (don't forget 
the \n). This command asks the client to give the script a copy of all com
mands sent from the client to the server. Now each time a command is sent 
from client to server, the script will get a "monitor <command>" string.\\
 

\\ 

A strange C command:



  fflush(stdout)



The stdout has something called a buffer. When you write to output device,
 it's not immediatly sent to it. For performance reasons, successive print
 to stdout are grouped. Most of the time, \n is enough to force sending of
 data, but we ensure all data are sent to client by flushing the stdout (f
orce empty buffer). In the future, when you think client didn't get a comm
and but the script did send it, ensure you flushed stdout.



Then comes a loop. This loop will read from stdin (where client puts infor
mations for the script) and copy them to stderr (our only access to consol
e since stdout is a connection to client). Because I don't want to use sca
nf I used the binary read and write commands. Stdin is the file handle 0 a
nd stderr is file handle 2. We first read up to 200 char from stdin and if
 we read something we write it to stderr. If we didn't read anything, that
 means we have lost the client (shouldn't happen) and we simply exit.



Since we asked to monitor all commands from client to server, we get them.
 These commands are our move commands and they use the same format as issu
e. If you run our first script while this second script is still running, 
you will still say hello world, but you'll get the following in your conso
le:



  monitor 1 1 say hello world



So client sends us lines made of



  monitor <repeat> <must_send> <command>



Now kill the script by typing command



  killscript <pathtoscript>



Then type __scripts__ to ensure it's stopped. Edit it, comment the line pr
intf("monitor\n"), compile and run the script again. Move and look at cons
ole. You see nothing. The script didn't ask anything so the client didn't 
tell it anything. Your script will only get that for which it asks.



Now try the following code:



  #include <stdio.h>

  

  int main (){

        char buf[200];

        int len;

        printf ("watch stats\n");

        fflush (stdout);

        for(;;){               

                len=read(0,buf,200);

                if(len)

                        write(2,buf,len);               

                else

                        exit(-1);

        }

  }





This time we are requesting commands sent from server to client. But there
 are far more of them. So watch takes as argument the beginning of all com
mands we want to get. Here we want every stat command from client. And in 
our console we see, when running script:



  watch stats food 398

  

  watch stats food 397

  

  watch stats food 396

  

  watch stats food 395



Wow! This mean we know when food is low and we can ask our script to invok
e restoration (remember the __issue__ command?) when our character's food 
gets below 50! No starvation anymore.



=== What's next? ===

There are two things you can still do with Script. The first is to request
 a bit of informations. The client then tells the script what it wants to 
know. The second thing is triggering an action of the script from client i
nterface. The command scripttell allows player to say something to a scrip
t. The script will get the exact command typed by player. See below for co
mmand list.



Commands to client

	

Here is a list of command the script can send to client.



  * watch <command type> - watch the given command from server-client prot
ocol. <command type> specifies the commands we want to watch. Set to empty
 to get all commands.

  * unwatch <command type> - unwatch the given command from server-client 
protocol. <command type> specifies the commands we want to watch. Set to e
mpty to get all commands.

  * request <data type> - Request a piece of informations from client memo
ry. Following is the list of <data type> allowed:

^ Data type ^ Comment                                                     
    ^

| range	    | Return the type and name of the currently selected range a
ttack |

    stat <type> 	Return the specified stats

    stat stats 	Return Str,Con,Dex,Int,Wis,Pow,Cha

    stat cmbt

	Return wc,ac,dam,speed,weapon_sp

    stat hp 	Return hp,maxhp,sp,maxsp,grace,maxgrace,food

    stat xp 	Return level,xp,skill-1 level,skill-1 xp,...

    stat resists 	Return resistances

    weight 	Return maxweight, weight

    flags 	Return flags (fire, run)

    items inv

	Return a list of items in the inventory, one per line

items actv 	Return a list of inventory items that are active, one per li
ne

items on

	Return a list of items under the player, one per line

items cont 	Return a list of items in the open container, one per line

map pos

	Return the players x,y within the current map

map near 	Return the 3x3 grid of the map centered on the player

map all 	Return all the known map information

map <x> <y> 	Return the information about square x,y in the current map

 



issue <repeat> <must_send> <command>

send <command> to server on behalf of client.

<repeat> is the number of times to execute command

<must_send> tells wether or not the command must sent at all cost (1 or 0)



issue mark <tag>

special case of issue command. only gets the command 'mark' and a object t
ag



issue lock <new state> <tag>

special case of issue command. Only gets the command 'lock' with 2 paramet
ers



draw <color> <text>

draw the following text on client interface with given color. Usefull for 
debugging and may help you to forget about using the stderr



monitor

unmonitor

start/stop monitoring commands send from client to server. Doesn't take an
y parameter.





	

	

Informations from client

	

	Here is an incomplete list of information strings send by client to scr
ipt. Those informations are sent only because the client asked them, excep
t for scripttell.



scripttell <yourname> <additional datas>

user send special command to this script specifically



monitor <repeat> <must_send> <command>

monitor mark <tag>

monitor lock <new state> <tag>

If monitor is on, <command> is a command send to server by the client with
 given repeat. mark and lock are special cases.



watch <command>  <datas>

You have put a watch on command or a part of command (like A to watch for 
AddMe command). This command was send by server and your are notified of i
t. Content of <data> vary on command and maybe very complex



request map <x> <y>  <darkness> <need_update> <have_darkness> <need_resmoo
th> <cleared> smooth <face_bottom> <face_middle> <face_top> heads <face_bo
ttom> <face_middle> <face_top> tails <face_bottom> <face_middle> <face_top
>\n",

Bunch of informations about square <x>,<y>



request map <x> <y> unknown

error occured.



request map pos <x> <y>

Tells script current position of player



request map end

Marks the end of a complete map transfer from client to script. Helpful.





** NOTE more command to be added here, incomplete liste **



	

	

Windows-specific notes

	

	Scripting works thanks to a patch from archaios. Known issues are:



    * If you want to run a Perl script for instance, you need to issue 'pe
rl <script_name.pl>, even if .pl is correctly seen as perl script.

    * If script doesn't output anything, try turning off buffering (in per
l $| = 1) or flush your pipe, or add a sleep at end of program. It seems
 Windows closes pipes at script termination before client gets time to gra
b output. 









IP-Address  : 72.4.41.2

Old Revision: none

New Revision: http://wiki.metalforge.net/doku.php/client_side_scripting:cl
ient_scripting_interface-basic_howto



-- 

This mail was generated by DokuWiki at

http://wiki.metalforge.net/





More information about the crossfire-wiki mailing list