[logo here]Client Scripting Interface - Basic howto |
||||||||||||||||||||||||||||||||||||
Purpose of this manual |
This Howto covers the scripting
interface present in gtk and x11 client under 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 program (the script) interact
client-side with your in-game behaviour. The script can have a copy of
messages sent from server to your client (there is a wide variety of
such messages), can have a copy of messages sent from client to server
(there is also lots of them), may request informations (on a item, a
map square ...) and finally can issue commands to the server. Lets call
those actions, respectively, server-client spying, client-server
spying, examining and interacting. |
|||||||||||||||||||||||||||||||||||
Pipes, stdout, stdin |
If this section make you puke at
second line, jump to next one. 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 script, php, anything you can think about. How can this be possible? Let's take a look at what happens when you type "echo hello world" on a shell prompt. Sure it writes on your terminal "hello world". And if you are in a graphical shell prompt? It appears in the graphical console! Some process changed 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 specified position. All this because when you ask to "write hello world to screen" you ask, really, to "write hello world to the standard output device". This standard output device is called stdout. There is also the stdin, which most of the time is your keyboard and stderr, the standard error device being most of the time the same as stdout. Ok, and now? Now what we use is exactly the same trick as the graphical console. when the client runs a script, it changes the script's stdin and replace the keyboard input with it's own orders (using a pipe). And it changes the stdout so instead of writing to screen, the script sends data to the client (using another pipe). And this is how any language can be used. Because every language can write to screen and read from keyboard! |
|||||||||||||||||||||||||||||||||||
First Scriptlearn to say hello |
Here we go for the first script.
We will do quite simple things. We will ask our character to say "hello
world" around. The script will be written in C because we simply need
to
choose a language. The script is quite simple:
Name it first.c, compile it and launch it in shell: tchize@Urd:~$ /home/tchize/script/firstNo surprise in the output (notice the \n at the end in source file). Now we are going to run it in the client. Start the client and log in your prefered server. When it's done, type in the following command: scriptsClient 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 example I typed: script /home/tchize/script/firstand you character says hello to the world. Nice, isn't it? Now try yourself with the following script:
Do you get the idea? every printf you make is a command to the client scripting interface. So now let's look at this command. It begins with issue followed by 2 integers. The command issue is part of the interacting of the Client Scripting Interface. It allows a script to send any command the player could send. There are lots of them i won't explain here. Just issue 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 is one, the command must be send, if it is zero, command may be forget in client-server process. Most user will set this to 1. |
|||||||||||||||||||||||||||||||||||
Second ScriptSpy Kids |
What to do next? As you can see,
our script don't wait very long after issuing commands. And it doesn't
get informations from the client at all. In fact it just hope it is
really speaking to the client. We are going to write a simple script
which 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 in a console or you won't see any result!
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_stopIf you type the command scripts in client you will see our script is still running. Let's look more closely at the code. We define a character buffer and a length. We will use the to read what client send to the script. Then script send to the client the command "monitor" (don't forget the \n). This command ask client to give the script a copy of all commands sent from client to 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 (force empty buffer). In the future, when you think client didn't get a command but the script did send it, ensure you flushed stdout. Then comes a loop. This loop will read from stdin (where client puts informations for the script) and copy them to stderr (our only access to console since stdout is a connection to client). Because I don't want to use scanf I used the binary read and write commands. Stdin is the file handle 0 and 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 the use the same format as issue. 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 console: 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 scriptkill <pathtoscript> Then type scripts to ensure it's stopped. Edit it, comment the line printf("monitor\n"), compile and run script again. Move and look at console. You see nothing. The script didn't ask anything so the client didn't tell him anything. Your script will only gets what he asked for. Now use following code:
This time we are requesting commands sent from server to client. But there are far more of them. So watch take as argument the begin of all commands we want to get. Here we want every stat command from client. And in console we see, when running script: watch stats food 398 watch stats food 397 watch stats food 396 watch stats food 395 Waw, this mean we know when food is below and we can ask our script to invoke restoration (remember the issue command?) when below 50 food! 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 interface. The command scripttell
allows player to say something to a script. The script will get the
exact command typed by player. See below for command list. |
|||||||||||||||||||||||||||||||||||
Commands to client |
Here is a list of command the
script can send to client. watch <command type> unwatch <command type> watch/unwatch the given command
from server-client protocol.
<command type> specify which specify the commands we want to watch. set to empty to get all commands. request <data type> Request a piece of informations
from client memory. Following is the
list of<data type> allowed:
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 tag
issue lock <new state> <tag> special case of issue command.
Only gets the command 'lock' with 2
parameters
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
any parameter.
|
|||||||||||||||||||||||||||||||||||
Informations from client |
Here is an incomplete list of
information strings send by client to script. Those informations are
sent only because the client asked them, except 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 it. Content of <data> vary on command and maybe very
complex
request map <x> <y> <darkness> <need_update> <have_darkness> <need_resmooth> <cleared> smooth <face_bottom> <face_middle> <face_top> heads <face_bottom> <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:
|