User Tools

Site Tools


client_side_scripting:client_scripting_interface-basic_howto

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
client_side_scripting:client_scripting_interface-basic_howto [2018/02/16 19:38]
karl [Commands to client] add missing request player, skills, spells
client_side_scripting:client_scripting_interface-basic_howto [2021/06/19 08:12] (current)
boingman [Using Scripts in the Client] Add further information about JXClient script management.
Line 1: Line 1:
 ====== Client Scripting Interface ====== ====== Client Scripting Interface ======
- 
 The **client scripting interface** can be used to control a Crossfire client using an external program (//​script//​). This interface can be used to extend the client or automate repetitive tasks (see [[client_side_scripting:​scripts|sample scripts]]). The **client scripting interface** can be used to control a Crossfire client using an external program (//​script//​). This interface can be used to extend the client or automate repetitive tasks (see [[client_side_scripting:​scripts|sample scripts]]).
  
-The script ​is started from the client ​and communicates ​by reading information from standard input and writing commands to standard output. ​A full list of commands ​can be found below. +The script ​communicates with the client by reading information from standard input and writing commands to standard output. ​Scripts ​can be written in any programming language. The same client scripting interface is used by the GTKv2 client and the JXClient. Any discrepancy should be reported as a bug.
  
-===== Getting Started =====+===== Using Scripts in the Client ​==== 
 +Several client commands are available to start, stop, list, and communicate with scripts:
  
-The ''​script'' ​command starts ​a script at the given path. The script must be executable (''​chmod +x'' ​with an appropriate shebang). For some languagesit may be necessary ​to write a wrapper ​script ​to execute the actual program.+  * ''​script ​<​path>​''​: start a script ​located ​at <path>. 
 +  * ''​scripts''​: list currently running scriptsalong with their numerical IDs 
 +  * ''​scripttell <id> <​string>'':​ send text to currently running ​script ​<​id>​ 
 +  * ''​scriptkill <​id>'':​ stop currently running script <id>
  
-The ''​scripts'' ​command lists running scripts ​with a numeric identifier. ​Scripts ​can be stopped using the ''​scriptkill''​ commandThe ''​scripttell'' ​command can be used to send arbitrary commands ​to a script.+  * JXClient only: 
 +    * ''​scriptkillall''​: stop all currently ​running scripts 
 +    * Unique alphanumeric substrings of <​path>​ may be used as <id> so that script names may be used in lieu of numbers 
 +===== Writing ​Scripts ​===== 
 +The script must be executable (e.g. ''​chmod +x'' ​with an appropriate shebang). For some languages, it may be necessary ​to write a wrapper script ​to start the program. Additionally,​ on Windows systems where the shebang is not supported, the player must provide a means of running such a script. For example ''​script python <​path-to-script>''​ if you are using python.
  
 ==== Hello World ==== ==== Hello World ====
Line 68: Line 74:
   fflush(stdout)   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.\\ ​+The stdout has something called a buffer. When you write to output device, it's not immediately ​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.+Then comes a loop. This loop will read from stdin (where client puts information ​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 they 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 your console: 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 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 your console:
Line 83: Line 89:
  
   scriptkill <​pathtoscript>​   scriptkill <​pathtoscript>​
 +
 +(The JXClient additionally recognizes partial script names as well as numbers and has an additional command scriptkillall to stop all currently running scripts in one go.)
  
 or or
 +
   scriptkill <​number>​   scriptkill <​number>​
  
Line 123: Line 132:
 ===== Reference ===== ===== Reference =====
  
-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.+There are two things you can still do with scripts. The first is to request a bit of information. 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.
  
  
Line 130: Line 139:
  
   * //watch <command type>// - watch the given command from server-client protocol. <command type> specifies the commands we want to watch. Set to empty to get all commands.   * //watch <command type>// - watch the given command from server-client protocol. <command type> specifies the commands we want to watch. Set to empty to get all commands.
 +    * Besides what is already documented, watch also supports "​tick",​ "​drawextinfo"​ (for most servers), and "​drawinfo"​ (for very old servers)
 +    * The "​tick"​ argument will provide the script with "watch tick <​integer>",​ as a tick of the server'​s clock.
 +    * "​drawextinfo"​ provide the script with text printed in the Messages text area. The format is "watch drawextinfo <​integer>​ <​integer>​ <​message>"​. For some very old servers (none of them which are online at the time of writing), "​drawextinfo"​ is not supported and you must fall back to "​drawinfo",​ which has the arguments "watch drawinfo <​integer>​ <​message>"​.
   * //unwatch <command type>// - unwatch the given command from server-client protocol. <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 empty to get all commands.
-  * //request <data type>// - Request a piece of informations ​from client memory. Following is a table of <data type> allowed:+  * //request <data type>// - Request a piece of information ​from client memory. Following is a table of <data type> allowed:
  
 <box round | Data Type Table> <box round | Data Type Table>
Line 156: Line 168:
 | spells ​     | Return a list of known spells, one per line | | spells ​     | Return a list of known spells, one per line |
 | stat paths  | Return spell paths: attuned, repelled, denied | | stat paths  | Return spell paths: attuned, repelled, denied |
-Note: player, skills, spells, stat path were added between versions 1.11 and 1.50 of the client.\\ 
-</​box>​ 
  
-FIXME \\ +Noteplayer, skills, spells, stat path were added between versions 1.11 and 1.50 of the GTK2 client.\\
-:!: In order to get the result ​of the request into your script'​s stdin you have to "watch request <data type>"​ before you do the request.\\ +
-:!: No, you do not need to watch requests (anymore?). The client will send the request to stdin of the script.+
  
   * //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 whether or not the command must sent at all cost (1 or 0). <​repeat>​ and <​must_send>​ are optional parameters. See [[#The Issue Command]] for more details.   * //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 whether or not the command must sent at all cost (1 or 0). <​repeat>​ and <​must_send>​ are optional parameters. See [[#The Issue Command]] for more details.
-  * //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.   * //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// - start monitoring commands send from client to server. Doesn'​t take any parameter. This goes to the script'​s stdin automatically.   * //monitor// - start monitoring commands send from client to server. Doesn'​t take any parameter. This goes to the script'​s stdin automatically.
   * //​unmonitor//​ - stop monitoring commands send from client to server. Doesn'​t take any parameter.   * //​unmonitor//​ - stop monitoring commands send from client to server. Doesn'​t take any parameter.
 +  * Special case ISSUE commands (these are issued without repeat and mustsend arguments):
 +    * //issue apply <​tag>//​ - Applies the object corresponding to <​tag>​.
 +    * //issue take <tag> [<​count>​]//​ - Retrieves the object corresponding to <​tag>​. If <​count>​ is given, it represents how many items to take. By default all items are retrieved.
 +    * //issue drop <tag> [<​count>​]//​ - Discards the object corresponding to <​tag>​. If <​count>​ is given, it represents how many items to drop. By default all items are discarded.
 +    * //issue mark <​tag>//​ - Marks the object corresponding to <​tag>​.
 +    * //issue lock <​newstate>​ <​tag>//​ - Locks or unlocks the object corresponding to <tag> in your inventory depending on the value of <​newstate>​. Valid values are 1 for lock and 0 for unlock.
  
 ==== Information from client ==== ==== Information 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. 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 data>// - user send special command to this script specifically+  * //​scripttell <scriptnumber> <​additional data>// - user send special command to this script specifically
   * //monitor <​repeat>​ <​must_send>​ <​command>//​   * //monitor <​repeat>​ <​must_send>​ <​command>//​
   * //monitor mark <​tag>//​   * //monitor mark <​tag>//​
Line 184: Line 196:
  
   * FIXME ** NOTE more information strings to be added here, incomplete list **   * FIXME ** NOTE more information strings to be added here, incomplete list **
- 
  
  
 ==== The issue command ==== ==== The issue command ====
-This command has it'​s ​particularities. I'll try to detail all I've encountered so far.+This command has it'​s ​peculiarities.
  
 Usage: Usage:
   issue [<​repeat>​ [<​must_send>​]] <​command>​   issue [<​repeat>​ [<​must_send>​]] <​command>​
  
-  * //<​repeat>//​ - Times the command should be issued. It's an optional numeric parameter. (Doesn'​t always work as expected) +  * //<​repeat>//​ - Times the command should be issued ​(not repeated after it's initial execution). It's an optional numeric parameter. (Doesn'​t always work as expected.
-  * //<​must_send>//​ - May be 1 or 0. If set to 1 the command will always be sent to the server. Otherwise it //may// be discarded under certain circumstances. ​+  * //<​must_send>//​ - May be 1 or 0. If set to 1 the command will always be sent to the server. Otherwise it //may// be discarded under certain circumstances.
  
 The next examples should clarify the use of numeric parameters. The next examples should clarify the use of numeric parameters.
Line 228: Line 239:
   issue 0 0 lookat 2 3   issue 0 0 lookat 2 3
  
-FIXME add a complete set of commands that work with <repeatand another of those that work without it.+  * FIXME Move "​issue ​<cmd<​tag>"​ documentation here, better formatted.
  
  
 ===== Platform-Specific Notes ===== ===== Platform-Specific Notes =====
  
-Scripting works thanks to a patch from archaios. ​Known issues are:+Known issues are:
  
     * If you want to run a Perl script for instance, you need to issue 'perl <​script_name.pl>,​ even if .pl is correctly seen as perl script.     * If you want to run a Perl script for instance, you need to issue 'perl <​script_name.pl>,​ even if .pl is correctly seen as perl script.
     * If script doesn'​t output anything, try turning off buffering (in perl $| = 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 grab output. ​     * If script doesn'​t output anything, try turning off buffering (in perl $| = 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 grab output. ​
  
 +===== A Few Thanks =====
  
 +Scripting was rendered initially functional with a patch from archaios and is being kept current by GTKv2 client maintainers Partmedia and crowbert, and JXClient maintainer Ragnor.
  
client_side_scripting/client_scripting_interface-basic_howto.1518831520.txt.gz · Last modified: 2018/02/16 19:38 by karl