Fwatch v1.1 scripting documentation

Usage instructions

Fwatch hooks file accesses made by OFP which allows you to make calls to Fwatch from OFP scripts. All commands for fwatch start with character ':', followed by a script command and possible parameters for it.

You can use both exec and loadFile commands from OFP to call Fwatch, for example:

Display fwatch version:
hint loadFile ":info version"

Execute script from http://www.site.domain/something.sqs:
[] exec ":file wget http://www.site.domain/something.sqs"

Conver _string to lower case:
_string = call loadFile format[{:string tolower "%1"}, _string]

Fwatch installation comes with an OFP addon pbo that adds a game logic to your mission editor. If you place it in your mission then the mission will not start at all for people who do not have fwatch installed. If the player has fwatch addon installed, but the fwatch hooks itself are not working then an error message will be displayed for him/her at the mission start.

The game logic also sets some global variables at init of the mission: KEG_Fwatch is true if Fwatch is active and working, KEG_Fwatch_version will include active fwatch version.

If you wish that your mission works without having fwatch installed, you can also do a check for fwatch's presence manually:

Place a file named "fwatch_check.sqf" containing the word "false" (without quotes) into your mission directory. When you try to access this file, fwatch will override it with a file containing "true". Therefore you can check Fwatch's presence with a script such as this:

_present = call loadFile "fwatch_check.sqf"
? !_present : exit
; Do things that require Fwatch here


General notes

Using strings

Strings should always be in quotation marks, ie:
good:

_x = call loadFile format[{:string tolower "%1"}, "HELLO"]
_x = call loadFile format[{:string tolower "%1"}, _mystring]
_x = call loadFile format[{:string tolower "HELLO"}]
_x = call loadFile format[":string tolower ""HELLO"""]
bad:
_x = call loadFile format[":string tolower HELLO"]
_x = call loadFile format[{:string tolower %1}, "HELLO"]
_x = call loadFile format[":string tolower %1", "HELLO"]


Filenames

Files can only be saved in the fwatch/mdb/ directory, all slashes and other invalid characters will be replaced with an underscore in file operations, ie:

call loadFile format[":file write /etc/passwd foo 1"]
would save foo=1 to fwatch/mdb/_etc_passwd

all filenames will be automatically converted to lower case.

You should always use unique filenames in file operations for you missions as missions can read, write and delete files from each other, ie:
good:

call loadFile format[":file write KEG_losthope_savegame.db foo 1"]
call loadFile format[":file write Kegetys_0001_savegame.db foo 1"]
call loadFile format[{:file write "KEG_%1_savegame.db" %2 %3}, missionName, "foo", foo]
bad:
call loadFile format[":file write savegame.db foo 1"]


General

OFP will crash if you try to use loadfile or exec with a filename longer than 132 characters.

Be careful with the usage of file wget, especially in multiplayer missions as it can easily cause large amounts of requests to the web server. For example if you do a request at the start of a MP mission, running the script on all players in a 20 player multiplayer game there will instantly be 21 requests made to the web server once the mission starts.

Pay special attention to where you need to run the scripts in a multiplayer game, for example if you are saving a variable to a file it maybe isn't necessary to save it anywhere else than in the server machine.

The asynchronous input commands do not know what script called them, so having multiple scripts running at the same time using them can cause keystrokes to be missed.



Command list:

info version
info debugout
string first
string last
string index
string length
string range
string tolower
string toupper
string toarray
file exists
file write
file awrite
file qwrite
file read
file vars
file readvars
file remove
file delete
file wget
input getkeys
input getkey
input agetkeys
input agetkey
input getmouse
input setmouse
db set
db get
db clear

Command reference

commanddescription

info version Return script engine version
example:
_x = call loadFile ":info version"
Value of _x would be 1.0 with fwatch v1.0

info debugout Output Win32 debug string
example:
call loadFile ":info debugout testing"

string first str1 str2 Return the index in str2 of the first occurrence of str1, or -1 if str1 is not found.
example:
_x = call loadFile format[{:string first "%1" "%2"}, "foo", "xx foo yy foo"]
Value of _x would be 4

string last str1 str2 Return the index in str2 of the last occurrence of str1, or -1 if str1 is not found.
example:
_x = call loadFile format[{:string last "%1" "%2"}, "foo", "xx foo yy foo"]
Value of _x would be 11

string index string idx Return the character at the specified idx.
example:
_x = call loadFile format[{:string index "%1" 1}, "hello"]
Value of _x would be "e"

string length string Return the number of characters in string.
example:
_x = call loadFile format[{:string length "%1"}, "hello"]
Value of _x would be 5

string range str i j Return the range of characters in str from i to j.
example:
_x = call loadFile format[{:string range "%1" 1 4}, "hello"]
Value of _x would be "ell"

string tolower string Return string in lower case.
example:
_x = call loadFile format[{:string tolower "%1"}, "HELLO"]
Value of _x would be "hello"

string toupper string Return string in upper case.
example:
_x = call loadFile format[{:string toupper "%1"}, "hello"]
Value of _x would be "HELLO"

string toarray string Return all characters in string as array elements
example:
_x = call loadFile format[{:string toarray "%1"}, "hello"]
Value of _x would be ["h", "e", "l", "l", "o"]

file exists name Return 1 if file fwatcher/mdb/name exists, -1 if not.
example:
_x = call loadFile ":file exists test.db"
Value of _x is 1 if file fwatcher/mdb/test.db exists, -1 if it doesn't

file write name var val Write var=val to file fwatcher/mdb/name
Return value: -1 if failed, 1 if succeeded
example:
call loadFile format[":file write test.db %1 %2", "foo", 1]
File fwatcher/mdb/test.db would contain foo=1

file qwrite name var val Write var=val to file fwatcher/mdb/name, without checking if value already exists in file
Return value: -1 if failed, 1 if succeeded
example:
call loadFile format[":file qwrite test.db %1 %2", "foo", 1]
File fwatcher/mdb/test.db would contain foo=1

Unlike file write, file qwrite does not check if the value being written already exists in the file. This is much faster, especially when writing to large files, but without the check you can write the same value into the file multiple times which can lead into unexpected behaviour when reading values.

file awrite name var val Appends val to var in file fwatcher/mdb/name
Return value: -1 if failed, 1 if succeeded
example:
(File fwatcher/mdb/test.db contains foo=[1,2])
call loadFile format[":file awrite test.db %1 %2", "foo", [3,4]]
File fwatcher/mdb/test.db would contain foo=[1,2,3,4]
This function can be used to overcome the 132 character limit in OFP filenames to write values longer than that to files. It should only be used to write string or array values, make sure the value you are adding is of the same type as the the value already in the file.

All the file handling functions in fwatch have a limit of 2048 characters per line, if the resulting line in the file would be longer than this the function will fail and return -1. If a value for var is not already in the file it will not be added.

file read name var Read value of var from file fwatcher/mdb/name
example:
(File fwatcher/mdb/test.db contains foo=1)
_x = call loadFile format[":file read test.db %1", "foo"]
Value of _x would be 1

file vars name Return array of all vars in file fwatcher/mdb/name
example:
(File fwatcher/mdb/test.db contains foo=1 and test="hello")
_x = call loadFile format[":file vars test.db"]
Value of _x would become ["foo", "test"]

file readvars name Read all vars and values from file fwatcher/mdb/name
Return value: -1 if failed, 1 if succeeded
example:
(File fwatcher/mdb/test.db contains foo=1 and test="hello")
call loadFile format[":file readvars test.db"]
Value of foo would become 1, and value of test would become "hello".

When reading local variables they need to be initialized first in the upper scope, ie:
(File fwatcher/mdb/test.db contains _foo=1)
_foo=0
call loadFile format[":file readvars test.db"]

file remove name var Remove a val from file fwatcher/mdb/name
Return value: -1 if failed, 1 if succeeded
example:
(File fwatcher/mdb/test.db contains foo=1 and test="hello")
call loadFile format[":file remove test.db foo"]
foo would be removed from fwatcher/mdb/test.db

file delete name Remove file fwatcher/mdb/name
Return value: -1 if failed, 1 if succeeded
example:
(File fwatcher/mdb/test.db contains foo=1 and test="hello")
call loadFile format[":file delete test.db"]		
File fwatcher/mdb/test.db would be deleted entirely

file wget url Get http URL
Return value: -1 if failed, 1 if succeeded
example:
[] exec ":file wget http://www.site.domain/something.sqs"	
You must wait at least one second between calls to file wget, or the function returns -1

input getkeys Return array of all keyboard keys pressed
example:
The user has keys Shift and X down
_keys = call loadfile ":input getkeys"
Value of _keys would be ["SHIFT", "X"]

input getkey key Return 1 if key is down, -1 otherwise
example:
_x = call loadfile ":input getkey X"
Value of _x is 1 if user has key X pressed

input agetkeys Return array of all keyboard keys pressed
Asynchronous version of input getkeys
example:
The user has pressed X since the last call of agetkeys
_keys = call loadfile ":input agetkeys"
Value of _keys would be ["X"]

This function does not work as expected when the user is holding down multiple keys at the same time. Therefore input getkeys should be used instead of this to get key combinations.

input agetkey key Return 1 if key is down, -1 otherwise
Asynchronous version of input getkey
example:
_x = call loadfile ":input agetkey X"
Value of _x is 1 if user has pressed X since the last call to this function or input agetkeys

input getmouse Return mouse state as array [xpos, ypos, left button, right button, middle button]
example:
mouse cursor is at 543x234 and left button is pressed
_mouse = call loadfile ":input getmouse" 
Value of _mouse would be [543, 234, true, false, false]

Positions are at screen coordinates and the cursor stops moving when it reaches a screen edge. Mouse button states work asynchronously, so if you query the state every 5 seconds and the button was clicked during this time the state will be true even if the button is not down at the moment.

input setmouse x y Set mouse cursor to position x y
example:
call loadfile ":input setmouse 500 300" 
Mouse cursor would be moved to coordinates 500x300

db set key value Set key=value in the dictionary
example:
loadfile {:db set foo [1, "two", 3]} 
"foo" will be set to [1, "two", 3]

db get key Get key from the dictionary
example:
loadfile {:db set foo [1, "two", 3]}
_foo = call loadfile {:db get foo} 
_foo will be now the array [1, "two", 3]

db clear Clears the dictionary
example:
call loadfile {:db clear} 
The dictionary will be empty now; every 'db get' will yield -1