Jump to content
Sign in to follow this  
celery

The wonderfulness of SQF

Recommended Posts

What makes sqf so much better than sqs? Some people seem to be so excited that my seriousness as a map maker has been questioned for my sqs usage. That really hit my self-confidence and right now I'm shaking and unable to work (I hope you're happy now). What properties make sqf totally superior to sqs in every way and how do I learn to script in sqf?

Share this post


Link to post
Share on other sites

I would aslo like to know what the asnwer to this is. I have read the discussion on the differences between an sqf script and an sqf function but not this specific question. I think it has to do with cpu usage and the fact that sqf are more efficient in that regard but I could be talking out of my behind.

I'm guessing that the more complicated the script or desired effect, the better it is to use sqf over sqs. if you are just doing something small like joining to a group or checking if a group is alive then I'm sure that the sqs is sufficient. BIS has declared the sqs deprecated but if you open the BIS missions that came with ArmA you will find tons of sqs scripts, and very few useful examples of an sqf. Make you maps the way you want, let the people that complain make the maps they want to make. After all is said and done you should be able to find help with optimizing the mission if it needs it.

Share this post


Link to post
Share on other sites

SQF scripts over SQS scripts have:

- Faster execution

- Better syntax (proper flow control, easier to read and write, exceptions, etc.)

- Same syntax as functions, so you only need to learn/remember one type of syntax instead of two different ones

Share this post


Link to post
Share on other sites

Evrything ive learned in SQS usage took me awhile, mostly by trial and error. The advantage of SQS by then, as irritating it was sometimes, was very user friendly, the language was logical and with english resembles.

From what i saw in SQF it uses a more mathematical language (speaking on the non-expert end user here), wich makes it a bit more harder to understand with all the { } symbols. I havent really catch when to use those for instance, because if u double quote "" "" it seems it has the same result.

At the end, and speaking for myself, i believe i need a dictionary of SQS / SQF confused_o.gif

Share this post


Link to post
Share on other sites

Me too. I can't seem to get it. The more examples I get the better I get at interpretting it. But sometimes I'm totally lost (which wasn't the case with scripts).

What does % do?

Share this post


Link to post
Share on other sites

For newguys to SQF (vets of SQS), please do not be frightened biggrin_o.gif

As much as SQS is friendly language, you will find SQF much friendlier.

Here is a few quick pointers that will help you:

A) SQS used a command on each line. SQF uses multi-line commands that end with a ; character. Because of this, you can write a single command broken out into multiple lines for easier reading.. i.e. <table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

if (  (_x>1) and

      (_y<2) and

      (_z!=3) ) then

......

B) The { } are code blocks. Most of the time, they represent scope. I'm currently in "programming mode" at work so I won't go into discussing advanced usage of "scope" for fear of mentioning something that is false for ArmA but true here at my work. You will find that scope is very handy for advanced usage, but normal usage you can just think of it as a way to seperate or group code together (like what is executed after an if...then condition) e.g.

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">if (x>1) then

{

  comment "This block is executed when true";

}

else

{

  comment "This block is executed when false";

};

C) SQFs are compiled meaning you cannot just "exec" them. When in the game, the engine must read an SQS file everytime you call it and then it is compiled into memory(sometimes alot more than once). So if you "exec" often you are in essence hogging up CPU cycles. By compiling an SQF file first, it is loaded from disk and read into memory once. Thus, each subsequent call uses what is already in memory. Much faster.

D) SQFs do not have a "GOTO" feature. Instead, we compile "functions" and call them when we need rather than just branching to a different section. This keeps the base code very tiny and "function" code more portable. To do loops, you use special commands like "do...while" which are IMO much easier than keeping track of all those "gotos".

Example:

SQS

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

_a = _this select 0

comment "Do a bunch of stuff"

if (_a>0) then {goto "DoSpecialThing"}

comment "Rest of Code after only runs if _a = 0"

goto "End"

#DoSpecialThing

comment "Only runs if _a > 0"

_a = getpos Player select 0

_a = _a + 10

#End

exit

Here is a combination of SQF script calling a function

SQF Script

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

_a = _this select 0;

comment "Do a bunch of stuff";

if (_a>0) then

{

  _a = [_a] call MyCompiledFunction;

}

else

{

  comment "Code after only runs if _a = 0";

}

SQF function compiled as MyCompiledFunction

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

_x = _this select 0;

comment "Do Something With _x";

_x = getpos Player select 0;

_x = _x + 10;

comment "return _x as a value";

_x

While this seems redundant in this example, think if the function was more elaborate (and alot bigger) and the base SQF contained alot of calls to several different functions. You can work on a function file and edit it and expect all changes to apply for all scripts that call it. No need to rewrite code often, no need to open a huge SQS file to work on one little #Section, etc...

Of course, if you are a beginner SQS scriptor that has never written more than 20 lines of code in a single file, than yes... SQF will not help you much.

Hope this helps some of you though.

Share this post


Link to post
Share on other sites

I've converted most of my scripts to SQF and found the largest challenge is restructuring some loops.  Since there's no "goto" you can't just hop from a loop, grab something and then go back.  This is why the flow control is better.  It keeps the game engine from having to skip all over the script.  Instead it goes through all the steps in order.

Now as to whether there's a discernable difference between SQS and SQF as to performance, I couldn't say.  My dedicated server seems to react the same way regardless of whether the mission is based on SQS or SQF.  In other words, once I get upwards of 30 people, the server performance drops a lot.

So in summary, if you're more comfortable with SQS, then don't worry about it.  If you can make a nice clean script in SQS, I really don't think you'd have a problem making it in SQF.  The syntax isn't that hard, you just have to think about it a little more.

Here's some examples that might help:

My old vehicle respawn script in SQS:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

?!local Server : Goto "end"

_vcl = _this select 0

_respawndelay = 10

_dir = Getdir _vcl

_pos = Getpos _vcl

_type = typeOf _vcl

Goto "Custom"

#start

_wait = _time + 150

~1

?CanMove _vcl && Count Crew _vcl < 1 : goto "Start"

?Alive _vcl && Count Crew _vcl > 0 : Goto "Wait"

Goto "Dead"

#Wait

~1

?Count Crew _vcl > 0 && Alive _vcl : goto "wait"

?!CanMove _vcl : Goto "Dead"

?Count Crew _vcl < 1 : Goto "DriverWait"

Goto "start"

#Dead

_delay = _time + _respawndelay

#DeadWait

~1

?Alive _vcl && Count Crew _vcl > 0 : Goto "start"

?_time < _delay : goto "DeadWait"

#Respawn

deleteVehicle _vcl

_vcl = _type createVehicle _pos

_vcl setdir _dir

Goto "Skip"

#DriverWait

~1

?(Count Crew _vcl < 1 && _time > _wait) || !(canMove _vcl) : Goto "Respawn"

?Count Crew _vcl > 0 : Goto "start"

Goto "DriverWait"

#Skip

goto "start"

#end

Exit

The updated version in SQF:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

private ["_vcl","_respawndelay","_dir","_pos","_type","_run","_crewWait"];

if (!local Server) exitWith {};

_vcl = _this;

_respawndelay = 20;

_dir = Getdir _vcl;

_pos = Getpos _vcl;

_crewWait = 150;

_wait = 0;

_type = typeOf _vcl;

_run = TRUE;

sleep 1;

for [{}, {_run}, {_run}] do

{

    while {canMove _vcl && count crew _vcl < 1} do

    {

         _wait = Time + _crewWait;

         sleep 1;

    };

    while {Count crew _vcl > 0 && Alive _vcl} do

    {

         _wait = Time + _crewWait;

         sleep 1;

    };

    while {canMove _vcl && count Crew _vcl < 1 && Time < _wait} do

    {

         sleep 1;

    };

    _delay = Time + _respawnDelay;

    while {!canMove _vcl && count Crew _vcl < 1 && Time < _delay} do

    {

         sleep 1;

    };

    if (count Crew _vcl < 1) then

    {

         deleteVehicle _vcl;

         _vcl = _type createVehicle _pos;

         _vcl setdir _dir;

         sleep 1;

         _vcl setvelocity [0,0,0];

         _vcl setpos _pos;

         sleep 1;

         _vcl setvelocity [0,0,0];

    };

};

The SQF code looks as long as the SQS, but that's because of the way I format it.  I've never been the most eloquent of scripters, but hopefully this'll give you some ideas.

Share this post


Link to post
Share on other sites
Me too.  I can't seem to get it.  The more examples I get the better I get at interpretting it.  But sometimes I'm totally lost (which wasn't the case with scripts).

What does % do?

% means "mod" and works in any script.

It gives the remainder when dividing rather than the result.

29 divided by 8 = 3 with a remainder of 5

thus

29/8 = 3

29%8 = 5

[EDIT] Just thought... % is also used with Format command.

Share this post


Link to post
Share on other sites
Guest

Thanks guys, this really is extremely usefull.

I can make scripts (I bet advanced users will say it is dirty or sucks or whatever, but it works smile_o.gif ), learned it from scratch without any programming knowledge. But have to admit the sqf stuff really made me nervous already only thinking of clicking on the link.

Posts like the ones above will make me and a lot of others be able to see the differences between sqs and sqf files and its a very good start to learn this all.

notworthy.gif

Share this post


Link to post
Share on other sites
Quote[/b] ]% means "mod" and works in any script.

It gives the remainder when dividing rather than the result.

29 divided by 8 = 3 with a remainder of 5

thus

29/8 = 3

29%8 = 5

When is that useful? I see the % used in a lot of sqf's but I never really know what it is doing.

And regarding the "format" which I think is its more common usage...

example:<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">;***************************************** INITIALIZATION *****************************************

#init

VBS_randomElement = {private["_r"]; _r = random (count _this); _r = (_r - (_r mod 1)); (_this select _r)}

VBS_getDirPos = {private["_a","_b","_from","_to","_return"]; _from = _this select 0; _to = _this select 1; _return = 0; _a = ((_to select 0) - (_from select 0)); _b = ((_to select 1) - (_from select 1)); if (_a != 0 || _b != 0) then {_return = _a atan2 _b}; if ( _return < 0 ) then { _return = _return + 360 }; _return}

VBS_distancePosSqr = {(((_this select 0) select 0)-((_this select 1) select 0))^2 + (((_this select 0) select 1)-((_this select 1) select 1))^2}

VBS_is_null = {private["_v","_r"]; _v = _this select 0; _r = true; if ((format["%1",_v] != "scalar bool array string 0xfcffffef") and (format["%1",_v]!="scalar bool array string 0xe0ffffef")) then {_r = false}; _r}

KRON_compassDir = {private["_d","_r","_c"]; _c=["North","NorthEast","East","SouthEast","South","SouthWest","West","NorthWest","North"]; _d=[getpos player,_this select 0] call VBS_getDirPos; _d=1+floor((_d-22.5)/45); _r=_c select _d; _r}

KRON_randomPos = {private["_cx","_cy","_rx","_ry","_cd","_sd","_ad","_tx","_ty","_xout","_yout"];_cx=_this select 0; _cy=_this select 1; _rx=_this select 2; _ry=_this select 3; _cd=_this select 4; _sd=_this select 5; _ad=_this select 6; _tx=random (_rx*2)-_rx; _ty=random (_ry*2)-_ry; _xout=if (_ad!=0) then {_cx+ (_cd*_tx - _sd*_ty)} else {_cx+_tx}; _yout=if (_ad!=0) then {_cy+ (_sd*_tx + _cd*_ty)} else {_cy+_ty}; [_xout,_yout]}

KRON_PosInfo = {private["_pos","_lst","_bld","_bldpos"];_pos=_this select 0; _lst=_pos nearObjects ["House",12]; if (count _lst==0) then {_bld=0;_bldpos=0} else {_bld=_lst select 0; _bldpos=[_bld] call KRON_BldPos}; [_bld,_bldpos]}

KRON_BldPos = {private ["_bld","_bldpos"];_bld=_this select 0; _bi=30; _bldpos=-1; while {_bi>-1} do {if (((_bld BuildingPos _bi) select 2)>2) then {_bldpos=_bi+1; _bi=-1;}; _bi=_bi-1;}; _bldpos;}

KRON_OnRoad = {private["_pos","_rdidx","_lst"];_pos=_this select 0; _rdidx=_this select 1; _lst=_pos nearObjects ["House",12]; if (count _lst==0) then {_rdidx=99}; _rdidx+1}

Thats from Kronzky's excellent UPS script. What does the format % do? the above is probably a bad example since its a complex script.

Share this post


Link to post
Share on other sites

The Biki has a very good description on the Format command.

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Syntax:

format [string, var1, var2 ...]

Parameters:

string: String - a string containing references to the variables listed below in the array. The references appear in form of %1, %2 etc.

var1: Any Value - variable referenced by %1

var2: Any Value - variable referenced by %2 a.s.o.

Return Value:

String - The full string is returned.

So as you see the format command takes a String parameter (this is the part often enclosed in quotes " ") and an indefinite number of other values. to reference to those values in order to include it at the place in the String parameter where you want them you need to reference them by the %-sign followed by a number. The number stands for the argument that you reference too. So %1 references to the first parameter behind the String parameter, %2 to the second, etc.

A little example:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

variable1 = 99;

hint Format["My grandma is %1 years old. Her name is %2", variable1, "Betty"];

The output would be:

My grandma is 99 years old. Her name is Betty

EDIT:

the % in mathematical operations stands for the modulus operator. As already explained it returns the remainder of a division. This is most useful in many cases. One use would be for example to divide numbers by 2 and then check if the remainder is 1 or 0. If it is 1 the number is an uneven number. If it is 0 the number is an even number.

There are many more uses for this but most of these are more advanced topics.

Share this post


Link to post
Share on other sites

Thanks for all the input! If there is no considerable performance difference, are there situations in scripting when sqf is more practical even if one is lots better at sqs?

Share this post


Link to post
Share on other sites
Thanks for all the input! If there is no considerable performance difference, are there situations in scripting when sqf is more practical even if one is lots better at sqs?

like the others explained SQF Syntax is always superior to SQS wink_o.gif Besides with SQS you can't write any functions (used with the call command) so it is better if you learn SQF, then you just need one Syntax and you can do functions and scripts alike. Besides it's not hard to learn. It's just another way of writing the things you already know combined with a lot more flexibility in controlling your script execution.

If you have the time and interest you could just do a C tutorial instead of waiting for someone to write a comprehensive SQF one (maybe there is already one but I dunno). If you learn C you'll get the hang of SQF in no time, plus you then even know a real programming language wink_o.gif

Share this post


Link to post
Share on other sites

I was talking along the lines where doing something in sqs is impossible or very hard at best compared to sqf. I'm not getting full speed into sqf because the differences on the map itself appear minimal.

Share this post


Link to post
Share on other sites
Quote[/b] ]Some people seem to be so excited that my seriousness as a map maker has been questioned for my sqs usage.

Well some people can take such things as syntax, way to seriously. If you can write something that does the job that’s fine. Anything else is just, pure self indulgence smile_o.gif

Quote[/b] ]I was talking along the lines where doing something in sqs is impossible or very hard at best compared to sqf.

sqf syntax used with the call command allows you to:

Repeatedly call the same bit of code over and over again in a script, without having to type it in multiple times or jump backwards and forwards using goto.

Access code globally, across all your scripts.

Returning a value before moving onto the next line of code.

Execute multiple commands within the same clock cycle.

Quote[/b] ]I'm not getting full speed into sqf because the differences on the map itself appear minimal.

In most cases your probably correct. Using the new syntax over the old syntax for scripts, won't give you any amazing increase in speed. But the new syntax is exactly the same as the old OFP functions. Functions are very useful and can even be pre-compiled before hand. That saves the game half the job of executing the code. There are other benefits to using functions at certain points in your code, so it is worth learning.

Not to mention, asking for help or sharing ideas on the forum. Will become a real pain in the a%*e, if people are not talking the same syntax.

Share this post


Link to post
Share on other sites

I think it depends what you want to do with your scripts. For quick tests i'd prefer sqs atm but that's because i'm not used to write sqf's. You surely don't have to use SQFs just for the sake of using a shiny new technology. tounge2.gif

I'm pretty sure a bad scripter can make a laggy SQF while a good scripter could move mountains with some SQS scripts. wink_o.gif

Share this post


Link to post
Share on other sites

Man, after looking at the code examples for both languages, I really hope they move to Python for scripting in the next generation. crazy_o.gifrofl.gif

Share this post


Link to post
Share on other sites

i think i've pretty much gotten all the syntax down for SQF. SQS is a different story. i still haven't figured out what the heck teh @ means in SQS.

Share this post


Link to post
Share on other sites
i think i've pretty much gotten all the syntax down for SQF. SQS is a different story. i still haven't figured out what the heck teh @ means in SQS.

@ means 'wait until condition is met':

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">@TheCowsComeHome

Wait until... wink_o.gif

Share this post


Link to post
Share on other sites

Could we request a simple dictionary to one brave soul in here?

Example:

SQS || SQF

"_x domove getpos guy" foreach grp1 || {_x domove getpos guy} foreach grp1

Share this post


Link to post
Share on other sites

The foreach command would be the same in either, AFAIK.

The main difference is the way if statements are handled, and loops are replaced by when...do and for...do.

Share this post


Link to post
Share on other sites
Could we request a simple dictionary to one brave soul in here?

Example:

SQS                                                      ||     SQF

"_x domove getpos guy" foreach grp1          || {_x domove getpos guy} foreach grp1

No, the first one does not work at all, anywhere. And SQF still uses the same exact commands (and they work the same way) as SQS, in fact some scripts in SQS would look identical in SQF (not including the mandatory semicolons), and as everyone has stated the only real difference in writing them is that you can't use "goto" (meaning you can't jump around to different parts) and everything has to go in order.

Share this post


Link to post
Share on other sites

While it may be true that SQF scripts are faster, I've always been asking myself - At what cost???

Normally, if you speed up one part of your software, another part will suffer (unless the first part was done totally inefficient).

So, since i just realized that under extreme loads my patrol script in SQF puts a much higher strain on the system than it does as an SQS one, I did some research.

Here's my test setup:

1000targets.jpg

One thousand spawned objects, each with an independent script running, to make it move.

Sure, you normally wouldn't have that many concurrent script running, but for testing purposes I assumed that, let's say, 10 simple scripts put as much load on the system as 1 complex one, so this might be a valid simulation of a few rather complex scripts (of course, that assumption could be wrong).

The results were pretty clear-cut:

SQF is faster, but only because it grabs so much of the CPU power that everything else will have to suffer.

During the object generation the whole system will be locked up, but then, when it's done, all the objects are there instantaneously. Whereas with an SQS script it will take a while to generate those 1000 objects, but the system runs quite fine with that happening in the background.

The same with the movements: The objects move more very nicely, and in-synch, when I use SQF, but the FPS drop down to 4-5. With SQS the movement is a bit more staggered, but the FPS stay at around 17/18.

The moral? SQF seems to be very good for quick and simple tasks that only take a fraction of a second. For longer, and more permanent tasks, that might not be as time-critical, but that should happen unnoticed in the background, SQS might still be the best choice...

Addendum: Here is another test setup, probably closer to a real-live scenario:

100 objects moving, via a script that contains 1,000 if..then statements (pretty nonsensical code, but the interpreter/compiler doesn't know that...).

With the SQS script the movement of the objects is pretty laggy, but the player still gets around 25FPS. With SQF on the other hand, the objects move smoothly, but there are only about 4 FPS left for the player! I guess that speaks for itself...

Share this post


Link to post
Share on other sites
Quote[/b] ]During the object generation the whole system will be locked up, but then, when it's done, all the objects are there instantaneously. Whereas with an SQS script it will take a while to generate those 1000 objects, but the system runs quite fine with that happening in the background.

To be honest, the tests you’re running are designed to fail from the start. As you said your self, you wrote a script to create hundreds of objects in an instant, of course it's going stop everything else. I could re-create exactly the same scenario with OFP, by comparing Exec with Call.

BTW I will use a simplified version for the sake of this example.

For example a loop like this:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">#Loop

~0.0001

_obj = "TargetTraining" createVehicle [_x+_off,_y]

_i = _i + 1

if (_i<_max) then {goto "loop"}

Is not the same as:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">for [{_i=1}, {_i<=_max}, {_i=_i+1}] do

{

 sleep .0001;

 _obj = "TargetTraining" createVehicle [_x+_off,_y];

}

So your comparing two different things. Again to get straight to the point, the sqf your using for object creation is just a bad use of commands for the job in hand.

Your correct in the sense that the new sqf syntax has greater potential to be abused. It was exactly the same with the @ and ~ commands in OFP.

I haven’t tested your particular scenario, but I'm sure you will get better results if you compare these:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_i=0;

_Max=100;

WaitUntil

{

Sleep 0.0001;

_obj = "TargetTraining" createVehicle [_x+_off,_y];

_i = _i + 1;

_i==_max};

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_i=0

_Max=100

#Loop

~0.0001

_obj = "TargetTraining" createVehicle [_x+_off,_y]

_i = _i + 1

if (_i<_max) then {goto "loop"}

But even then, if you time your Exec loop and find it takes 100 seconds to create 100 objects under normal circumstances. Then you should revise your sqf script accordingly:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_i=0;

_max=100;

WaitUntil

{

Sleep 1;

_obj = "TargetTraining" createVehicle [_x+_off,_y];

_i = _i + 1;

_i==_max};

Share this post


Link to post
Share on other sites

My point is: SQF is extremely greedy...

Yes, you could rewrite the "make" script in the example to be slower, but that's not the point.

What if I invoke an SQF script from the init line of a hundred units?

SQF will grind your system down to a halt. SQS doesn't...

And what about the movement part of the example?

SQS is still leaving the player a generous 24FPS. SQF, on the other hand, leaves you with all but 5! (And it doesn't make much of a difference if you use a for...do loop or a waitUntil.) In both cases SQF grabs way too much processor power to the game to be left playable.

Show me a working test scenario of where SQF performs more gracefully than SQS, and I will "un-dump" the SQF version of my patrol script. (And I'm not talking about little, trivial tasks, where it doesn't matter in the first place how it runs, but a fairly complex script that is deployed massively.)

Mind you, I would *love* to use SQF (as probably any programmer would), but not at the cost of playability. That always has to come first. Not my preferences as a programmer.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×