Jump to content

Sign in to follow this  
rwillis

SQF functions over SQF scripts?

Recommended Posts

I think you guys are getting me a bit wrong here smile_o.gif

I'll explain what I mean by the example of the question that MrZig asked.

He wanted to know which of the commented-out lines would be the best to use:

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

~0.01

;call ZigPreprocessedCode

;[] execvm "ZigCode.sqf"

;[] exec "ZigCode.sqs"

goto "lp

Now having some insights into this topic, can you honestly give him a straight and short answer in form of rules, that is really true for what he's trying to do?

I think I can't and here's why:

If I tell him that using functions for everything is good coding practice and he goes on and implements 50 functions that may be a bit heavier than the example he posted and runs them every 0.001s, can he expect that to be working fine?

The advice or the rule itself may have its merits but then he doesn't know in what cases it has merits and therefor can't use the rule for his benefit. To do that he needs to know the reasoning behind the rule.

Now I tell him to use scripts as much as possible and he's running the same 50 scripts every 0.001s and doing a file access every time (or is that cached in ArmA*?). I doubt that he'll be happy with that rule either, at least as long as he doesn't know the reasoning behind it.

What am I supposed to tell him? For some things there is just no straight and short answer that is generally true.

That leaves me with basically three options:

- Explain him how (according to my experience) the thing works under the hood and where he should look for traps so that he can go and not just apply it to his current problem but maybe for all the coming problems that he's going to face in that direction as well.

- Tell him to just try for himself and see what happens because doing so would probably only take about 15 minutes and he'll get results that specifically match his problem and for sure is faster than me trying to explain the whole thing. At least this will solve his current problem and maybe even give him some insights to tackle the next one.

- Tell him that it doesn't really matter and he should throw a dice to decide. For me that's the same as telling him to go by some kind of rule that might or might not apply to his specific case, after all I don't really know the details to judge myself if such a rule would be good to apply there or not. Also the time it takes to get the details (if he's even willing to share them) will probably take longer than the first two options above.

And for rules or good practices, you say it yourself:

  (CrashDome @ Dec. 14 2006,16:29) said:
They [the coding practices] are in fact a development of what is optimal underneath the language you are using.

What kind of language?

ArmA scripting, C++, Haskel or even Assembler for some weird Motorola chip?

You need to know the reasoning behind those rules and what they were geared for to be optimal to use them properly.

In fact, it might even be better to write spaghetti code than applying coding practices from other languages/project types/plattforms/..., because the reasoning behind every rules is anything but universal.

Hell, even naming all your variables x1, x2, x3... might be a good idea for some cases, so not even naming conventions are universal. The idea behind such rules is usually much more universal than the rule itself, but you don't teach someone the idea by just telling them the rule. For that you need to explain things.

Rules are crutches for the brain to remember the reasons behind them, and you need them just because access to human memory banks is organized in such a weird way wink_o.gif

In the end every piece of code has its own set of things it needs to achieve and therefor you can't just apply general rules without knowing their reasoning.

In most of the cases trying to get an average response time of 0.04s from a database is just wasting project resources while most time it's essential for a game.

To stay with your example of the birds and the nest:

If you just tell them that it's generally a good idea to flap with the wings, they might as well jump out of the nest thinking they can fly because they're flapping with their wings, only to crash into the next best thing since they didn't know anything about steering or landing. The result will be the same: Hurt bones.

I'm not saying to just push them out, but to tell them what it takes to fly. After all they asked about it, so they should be prepared to get the full deal. After that they can still decide if they just want to sit in the nest and practice some flapping, but at least they know then what it takes to get it done.

*are calls like loadFile, exec or execVM cached in ArmA?

Somewhere Kegetys posted that tricks like fwatch don't work with ArmA. Maybe because file access is cached now?

Share this post


Link to post
Share on other sites

I think we are getting each other wrong somewhere along the lines. I really don't want to debate anymore, but I will say you are taking things I say a bit too literally (i.e. I never used the word "rules" - I used the term "patterns and practices" - they might mean the same to you, but not to me). When I speak of language, I fully realize C++/C#/Java patterns don't apply completely to things like Motorola's Assembly language let alone ArmA/OFP. All I wanted to suggest is that new guys should follow some guidelines to eliminate most of their problems off the bat. MrZigs example fully fits into this situation. As I suggested to him, functions are the way to go in this situation and *hypothetically speaking* had he been using certain practices, he may have still asked the question simply for the sake of learning more. The difference is that without using certain practice behavior he was forced to ask, whereas the new guy who doesn't want to ask (don't ask me why someone wouldn't want to know - but for arguments sake) can use the practice and still result in similarily efficient code. I understand they don't apply all the time it's all just a matter of weeding out some bad coding behavior while teaching some fundamentals.

Seriously, you need to relax a bit on your viewpoints. It's impossible to teach everyone how everything works - especially if such a person is unwilling to learn that much.

Either way you feel about it is fine, but I will continue to preach what I practice.

Share this post


Link to post
Share on other sites

@CrashDome:

I'm not trying to teach everyone how everything works, nor do I intend to tell anyone what he's supposed to do.

I was merely explaining my point of view in something where it seemed that we didn't agree. The following posts were just to clear things up and I think we clarified what each others point is. That's all I intended to do smile_o.gif

Now back to the topic of functions and scripts.

For OFP, I think using a function call would be the right thing to do, if the function is just doing what MrZig showed as an example for the function.

Also using lots of such frequent function calls can give performance problems, because functions are run in one piece and either end or get aborted. Especially if the function does some more things this might become a problem.

Also to me it looks like it's not the best way to design a function, but then we don't really know how the real one looks like. It's just that the sample code suggests that this could be done in a cleaner way (here's where patterns and practices come into play).

Now for ArmA that might be different again. Especially after the findings about using the sleep command in functions.

To me this suggests that scripts and functions are much closer in how they're run in ArmA than they were in OFP. At least for the new script type.

Share this post


Link to post
Share on other sites
  (UNN @ Dec. 13 2006,00:48) said:
  [b said:
Quote[/b] ]If you need a return from a script then you can also give it an array as parameter where the script puts the result(s) in. Since the array is given to the script by reference, you can read out the return values afterwards.

Yep, but it's has some restrictions. For example, you can't use + or - on _resultArray, otherwise you loose your pointer to it.

Actually, there's a very simple way around that, just go multidimensional.

myArray = [[val1, val2, val3, val4]]

To add a value inside a script which has been passed this array:

_passedArray set [0, _passedArray select 0 + [val5]]

The result:

[[val1, val2, val3, val4, val5]]

To call a specific value from this result:

val = (myArray select 0) select X

Share this post


Link to post
Share on other sites

I know about multi dimensional array pointers, I’ve been using them for years.

ATCOpen.sqs:

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

_Pointer=_This Select 1

;If it's already opening or closing wait

#L

~1

If ((_Plane animationphase "mtydoor" < 1) And (_Plane animationphase "mtydoor" > 0)) Then {goto "L"}

;If it's open then skip to the end

If (_Plane animationphase "mtydoor"==1) Then {goto "Exit"}

_Plane animate ["mtydoor",1]

~5

#Exit

(_Pointer Select 0) Set [0,True]

_Pointer is a simple array of [[False]]. Used to handle animation lengths of varying degrees. Although it's redundant now, as Arma allows you to detect the end of another script.

Your correct in the example you provided, although if val5 was an array that was being pointed to from elsewhere, you would loose that pointer. BTW if you haven't tried it already. If want to subtract a value and maintain the pointer, you can use:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">(_passedArray Select 0) set [5,"DELETE"]

_passedArray set [0, (_passedArray select 0)-["DELETE"]]

But that wasn't the example Romulus posted and even then, the topic was about functions and scripts, not array pointers. Plus, I have to restrain myself when it comes to array pointers. They were a rarely used feature in OFP, so it's great to see them getting the usage they deserve. I’m likely to get carried away…..

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

ARRAY02=[[],[]]

ARRAY01 Set [0,ARRAY02]

ARRAY02 Set [0,ARRAY01]

Edit:

Sorry Romulus, I forgot to mention:

  [b said:
Quote[/b] ]are calls like loadFile, exec or execVM cached in ArmA?

Somewhere Kegetys posted that tricks like fwatch don't work with ArmA. Maybe because file access is cached now?

Looks that way, although you can force it with loadfile. But you have to get the timing right, if you don't delay the calling loop, you will get a shared file violation.

If fwatch can wait until the file is released? Then the delay could be kept to a minimum.

Share this post


Link to post
Share on other sites
  (UNN @ Dec. 15 2006,18:21) said:
I know about multi dimensional array pointers, I’ve been using them for years.

I had assumed you knew that. I was just pointing out, for the benefit of anybody who didn't, that there is a workaround. Mostly to illustrate the point that any limitations can be worked around with proper coding practices and a little creative thought.

  (UNN @ Dec. 15 2006,18:21) said:
Your correct in the example you provided, although if val5 was an array that was being pointed to from elsewhere, you would loose that pointer.

1st, making the assumptions that argument requires, you shouldn't lose anything, In my example, I wasn't modifying the array containing val5 at all.

2nd, val5 was a value inside of an array, not an array. Therefore, there's no such pointer, regardless of the contents of val5. In practicality, val5 is a placeholder that I used for example purposes, and not a global variable. It would be something like _myUnit, or _myPos, or whatever in a real script.

Share this post


Link to post
Share on other sites

Hello

The following message is about issuing the command "sleep" in preprocessed .sqf functions. It is the result of various experiments I carried out and what I have found may be wrong. Any con-/in- firmation is welcome.

<ul>[*]Results

"Sleep" works in preprocessed .sqf functions if those functions are called from other not preprocessed .sqf. Not if they're called from either an .sqs or a trigger or a preprocessed .sqf.

[*]Testing Methods

I created a preprocessed .sqf called "test".

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

In the init file:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">SpawnBuild=compile preprocessfile "SpawnBuild.sqf";sleep 1;[] call test

As you may know, init files can be indifferently .sqf or .sqs.

If it's an .sqf, the hint is displayed. If it's an .sqs, the hint is displayed, but with an error message (the "error in general expression" one).

A radio trigger with "[] call test" in its activation field always resulted in the same error message.

To confirm these first results, i created a test0 file containing the following line:

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

I made it a non-preprocessed .sqf, and typed <table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">blabla=[] execVM "test0.sqf"in the activation field of my trigger.

No error message, the hint appeared.

I then changed test0 to an .sqs, changing the activation field of my trigger accordingly:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">[] exec "test0.sqs"

The hint was diplayed, but with the same error message.

I also created another test1.sqf that I preprocessed with "[] call test" in it. You then get the error message too.

[*]Summary (TO BE CONFIRMED! )

<ul>[*]"Sleep" in non-preprocessed .sqf always works;

[*]it will even work in preprocessed .sqf when those .sqf are called from other non preprocessed.sqf;

[*]"sleep" will work in preprocessed .sqf if that .sqf is called from either a trigger or an .sqs or another preprocessed .sqf, but it'll cost you an error message - and a freezing game for a while on some occurrences.

Hopefully this is of some kind of interest, if only because the distinction between preprocessed .sqf and not preprocessed .sqf seems to be extremely important.

But once again, please someone confirm this!

Regards,

Igor.

Share this post


Link to post
Share on other sites

So should we only use .sqf files now (instead of the old .sqs ones)?

Share this post


Link to post
Share on other sites
  (rwillis @ Dec. 16 2006,14:29) said:
So should we only use .sqf files now (instead of the old .sqs ones)?

That's what the biki says. Although there is some inconsistancys, it's pretty consistant about that.

It says pretty explicitly that the old sqs format is depreciated now which is generally understood to mean that it's strictly there to enable old stuff to run. Usually, it also means that it's unsupported, and won't be around in future versions.

For your convienince, here's a script I wrote in ofp that I have just converted to ARMA:

bring_out_your_dead.sqs

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">; removes the body after the specified number of seconds passed

; in this case, 5 mins

_removeBodyAfterTime = 300

; should be the unit that you called this script on

_unitToRemoveWhenDead = _this select 0

; circles till the guy dies;)

; pretty coarse detection here, no need to be too precise

#vultureLoop

~15

? alive _unitToRemoveWhenDead : goto "vultureLoop"

; wait the specified amount of time to mop up

~_removeBodyAfterTime

[_unitToRemoveWhenDead] join grpNull

deleteVehicle _unitToRemoveWhenDead

CSL_Bring_Out_Your_Dead.sqf (arma script, used by execVM)

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

private ["_removeBodyAfterTime", "_unitToRemoveWhenDead"];

// should be the unit that you called this script on

_unitToRemoveWhenDead = _this select 0;

// removes the body after the specified number of seconds have passed

// in this case, 5 mins

_removeBodyAfterTime = 300;

// waits till the guy is dead. Pretty coarse detection, we don't need fine precision here.

while {alive _unitToRemoveWhenDead} do

{

sleep 30;

};

// wait the specified amount of time to mop up

sleep _removeBodyAfterTime;

// hideBody makes the body sink into the ground

hideBody _unitToRemoveWhenDead;

// wait a few secs for the body to be hidden

sleep 10;

// remove the body permanently

deleteVehicle _unitToRemoveWhenDead;

Looking above, you can see that the conversion is pretty easy once you understand the function structure.

I have to say thank god we no longer have to use gotos to simulate loops and case structures and stuff...

Share this post


Link to post
Share on other sites

Thanks!  This is what we need more of in the biki...  more examples.

So that checks every 30 seconds to see if that unit died?

Share this post


Link to post
Share on other sites

@Igor Drukov

Take a look at the preprocessFile in the wiki. The command does not effect how each command is called, just how it's formatted before calling.

Putting that aside, I tested the same batch of commands:

you can call any of the following from within a script using execVM, without any errors and expect to see the correct output:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Call Compile "Sleep 5; Player SideChat Format [""1st Sleep Time %1"",Time]; Sleep 5; Player SideChat Format [""2nd Sleep Time %1"",Time]; Sleep 5; False"

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Call Compile LoadFile "SleepTest01.sqf";

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Call Compile PreProcessFile "SleepTest01.sqf";

Where the file SleepTest01.sqf contains this:

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

Player SideChat Format ["1st Sleep Time %1",Time];

Sleep 5;

Player SideChat Format ["2nd Sleep Time %1",Time];

Sleep 5;

False

Now if you move any of the above lines into the init field of a unit, you get the following error:

  [b said:
Quote[/b] ]Error Generic error in expression

If you move the same code into a trigger and call it, you get the same error. In both cases, both the sidechat commands are executed, only without the delay from sleep. The reason you don't see the sidechat output if run from the init field is, sidechat is executed before the screen initialises during the missions startup.

Just to test the point, I created another function called SleepTestInit.sqf, containing the follwoing line:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Call Compile PreProcessFile "SleepTest01.sqf";

SleepTestInit.sqf was called from a script using execVM:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Call Compile PreProcessFile "SleepTestInit.sqf";

Again, everything worked as expected.

As a final test, I added this line to the init field of a unit:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">Sleep01=Compile LoadFile "SleepTest01.sqf"; Spawn01=[] Spawn Sleep01

This worked as expected, with the sleep commands and sidechat providing the correct output.

The conclusions I came to from this are quite complex. Complex enough at least, for me to have to think carefully about how they should be explained. The way I see it, it's all down to the scope of a script. Scripts have parent scopes, so sleep works with the call command, from within a script or function that inherits from that parent scope.

The init fields and triggers don't have a parent scopes, so you can't use sleep with the call command.

However, if you use the Spawn command from and init field or trigger, you do create a parent scope allowing you to use sleep directly from an init field e.t.c

Ok, that's probably not very clear. But I think it would take more than an hour or so to formulate a proper explanation of what I think scope is, before I could beging on the commands themselves. Plus anyone just starting out in scripting, should be strongly advised, not to read it.

In short, as far as beginners are concerned, they should be told they can't use the sleep command with the call command. If anyone does want to use call and sleep together (I can think of only one reason to do so, that would probably work) then you should be discreet about it smile_o.gif

BTW: The same thing applies to theWaituntil command to.

Share this post


Link to post
Share on other sites
  (rwillis @ Dec. 16 2006,18:22) said:
Thanks! This is what we need more of in the biki... more examples.

So that checks every 30 seconds to see if that unit died?

Yes, and if he has, wait the specified amount of time to remove the body.

I generally disagree about examples in the biki though, unless a special section is added for them.

Others may disagree, but I feel that the biki should be considered more of a community manual, which talks straight facts. Soon enough, we'll have plenty of examples all over ofpec and these boards.

Actually, I'd like to hear peoples opinions on that subject. I wonder if I'm alone in that school of thought, or if it's more of a general unspoken consencus.

Share this post


Link to post
Share on other sites
  (UNN @ Dec. 17 2006 @ 02:04) said:
Take a look at the preprocessFile in the wiki. The command does not effect how each command is called, just how it's formatted before calling.

Well, this is confusing because I've never implied such a thing.

The more general issue I am raising is that apparently the same lines of codes and the same functions will or will not work depending on where they are called from. That is what my original message amounted to.

And if I'm not mistaken you are saying exactly what I say too.

Now I think a WAY stricter definition of what a function and what a script are needs to be made. It came to mind after reading your tests with the "spawn" commands in a unit's init line.

If you take a look at the Spawn command, you will have noticed the description says:

  [b said:
Quote[/b] ]The new script (Function) is running in parallel, spawn does not wait for it to be done

This is extremely important! Here is how I see things - I'll be trying to be as simple as I can, I hate jargon.

But first, a little terminology.

I would personnally be in favour of restricting the use of "functions" to lines of code which, when executed, "halt all other game engine processes until they have completed their instructions" (from the Biki).And to my knowledge, this is only possible with preprocessed/loadfiled .sqf files executed with "call" (and no other command! ).

For obvious reasons, a preprocessed file containing the "sleep" command, even though it is executed with "call", will behave as a script, and so should not be called a function.

All the rest, strictly speaking, is a script.

Now I think a useful way of imagining ArmA's coding environment is to imagine a gradient, with .sqs on one end and .sqf on the other.

<--------------------------------------------------------->

.sqs .sqf

From there, a few things must be borne in mind:

<ul>[*] The editor is an .sqs environment.

[*] the behaviour of a script pertains to the environment it has been called from.

[*] certain commands belong to one end of the gradient EXCLUSIVELY ("exec" for .sqs, "sleep" for .sqf for instance).

[*] other commands port one behaviour from one end to the other ("spawn" allows .sqf behaviour from an .sqs environment).

All this -I think!- rather clearly explains the strange behaviour of "sleep" in certain circumstances.

At least, that's the way I see it all... I hope you will find it useful too!

Regards,

Igor.

Share this post


Link to post
Share on other sites
  [b said:
Quote[/b] ]Well, this is confusing because I've never implied such a thing.

Oh, sorry. I thought this line was pretty explicit though?

  [b said:
Quote[/b] ]the distinction between preprocessed .sqf and not preprocessed .sqf seems to be extremely important.

Considering we are talking about the sleep command, that was certainly the way I read it.

  [b said:
Quote[/b] ]And if I'm not mistaken you are saying exactly what I say too.

Yep, I even said it a few post back from that to. It was just confusing when you talk about preprocessing the file at the same time. As the sleep command acts the same way, regardless. But as long as it's made clear, then it will save a load or problems for people later on. So it's not necessarily a bad thing, to keep re-iterating it.

  [b said:
Quote[/b] ]The editor is an .sqs environment.

Yeah, kind of. At least the init fields and trigger conditions e.t.c are. Although it's limited, sleep and waitUntil being some examples and local variables, another.

Share this post


Link to post
Share on other sites

Hum.

I won't be nit-picking about how absurd it is to make entailments from hedged utterances or to confuse implicit and explicit, since we agree and since it wouldn't serve the general purpose of this thread.

Still, what I could read about nowhere (and this doesn't mean it doesn't exist) is how where a given code is executed from affects its execution. Once again, exactly the same lines of codes executed from different environments will or will not produce error messages.

Also, I truly believe the term "function" should be reserved exclusively for time-halting files, i.e. preprocessed files, executed with call, and not containing any time-related variables such as "sleep" or "waitUntil".

Anyway, I'm off to listen to Stevie Wonder's Innervisions - it's got some appropriate songs in it.

Regards,

Igor.

Share this post


Link to post
Share on other sites
  [b said:
Quote[/b] ]where a given code is executed from affects its execution

Second page of this thread, ninth post down.

  [b said:
Quote[/b] ]I tried to execute the same function from an objects init field, that didn't work. The sleep keeps throwing up an error. From a script it's ok.

But it's not like I went into any detail and it's a crude explanation on my part. So there is no harm in us expanding on it.

If by preprocessed file you mean:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">MyFunc=Compile PreProcess "Function.sqf";

Call MyFunc;

Then yeah, as a basic rule, it works for me! I've yet to check if you can now load a function from an addon, using preprocessFile. But assuming there is no major over head, then why not? If your not using C(++) syntax or comments, then sometimes there are better alternatives,  that don't use preprocessFile. But work exactly the same as any other functions. But that’s best left for other topics.

  [b said:
Quote[/b] ]Anyway, I'm off to listen to Stevie Wonder's Innervisions - it's got some appropriate songs in it.

Well as long as doesn't harm anyone...permanently. Then I guess, even listening to Stevie Wonder can be forgiven smile_o.gif

Regards

Share this post


Link to post
Share on other sites

Before you guys debate any further. Can anyone confirm that functions (using preprocessfile and call command from within an sqs file or init line) still halt the engine code? OR stop executing after 10,000 loops (or whatever that number was)?

We've all made that assumption that nothing in that department has changed from OFP, but I am getting a theory that they in fact do not do that anymore.

I honestly am starting to think that this is much simpler than we think. My new theory is that the function parsing/compiling engine has simply been updated to accomodate parallel execution and unlimited looping. So basically it is the same as OFP sqs only with different syntax and capability (return values and better efficiency).

I only base this theory on the idea that no one has confirmed halting of code via a called function which IMO is the only thing that seperates SQF Functions from SQF "Scripts". If we eliminate that seperation it all becomes very clear to me.

Share this post


Link to post
Share on other sites

Well preprocessing a function with:<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">private ["_i"];

_i=0;

while {_i<11000} do {_i=_i+1};

hint format ["%1",_i];

returns 10,000.

As to whether they halt the engine, my guess would be yes after observing a slight freeze for heavy functions. But I can't think of a reliable way to prove it.

[edit]

Not preprocessing the file and execVM it also returns 10,000.

[/edit]

Share this post


Link to post
Share on other sites

OK, in light of this confirmation, I am doing a 180 and going to develop a different theory of how this engine is designed.

IMO, there is definately a few different environments - probably based on class type. Triggers and Init fields are properties of a class. When you "exec", "execVM", or "spawn" something you are calling directly rather than calling code from a property.

Before I confuse anyone further, I am going to try and figure this out (with help of course! - thanks Igor).

Share this post


Link to post
Share on other sites

I'm not 100% positive, but I think that execVM also stops engine execution until it either finishes, hits a sleep command, or has to output something.

I noticed this when I accidently made an infinite loop. I didn't think to test it further, but immediatly fixed it.

Now that I think of that, I need to test that out.

If I'm correct on that, it would mean that the only difference between an sqf script and an sqf function is wether or not they return a value, and potentially, the results of a sleep command.

Now, I've just got to think of a clevar **** way to do that test reliably.

Share this post


Link to post
Share on other sites
  (ColonelSandersLite @ Dec. 19 2006,02:25) said:
I'm not 100% positive, but I think that execVM also stops engine execution until it either finishes, hits a sleep command, or has to output something.

I noticed this when I accidently made an infinite loop.  I didn't think to test it further, but immediatly fixed it.

Now that I think of that, I need to test that out.

If I'm correct on that, it would mean that the only difference between an sqf script and an sqf function is wether or not they return a value, and potentially, the results of a sleep command.

Now, I've just got to think of a clevar **** way to do that test reliably.

Igor ran some tests for me last night. We've decided that the sleep command hs zero input on parallel execution. It will certainly halt a function called with 'call' but the script which called it is also in a state of suspension. The only method to halt the engine is with 'call' and even with the sleep or waituntil command the engine may continue but the original script is waiting for that function to finish, thus the original Script is still halted. However, execVM and spawn do not halt any code so anything is run parallel - let me explain:

Script A (SQS with exec or SQF with execVM or spawn) executes and you reach a point where Function A is called (via call command). Script A is halted as is the engine until call returns a value. If the Function should implement the sleep or waituntil command, Script A remains halted waiting for the call command to finish but the engine continues. Once sleep or waituntil is over, the function continues and halts the engine again.

If we take the same story but instead of Function A - we replace it with Script B (same text file executed with compile command and spawn) then the two scripts run in parallel. Script A *may* finish before Script B. This is why you need to use the scriptDone command to make sure the script is complete if you want to wait for it in Script A. ExecVM seems to produce the same behavior *except* that it also compiles the code and eliminates the need for compile or such before spawn. The drawback to that is if you loop your script and call Script B multiple times, you are better off compiling before the loop and spawning it as needed.

Share this post


Link to post
Share on other sites

You know, I knew all of that (well, 99% of it), and looking back, I have no clue what the hell I was thinking when I wrote that. I'm just going to chalk it up to being tired and my mind on something else.

I made a few bonehead moves last night, so that post isn't the only thing...

Share this post


Link to post
Share on other sites
  (CrashDome @ Dec. 19 2006 @ 15:59) said:
Igor ran some tests for me last night. We've decided that the sleep command hs zero input on parallel execution. It will certainly halt a function called with 'call' but the script which called it is also in a state of suspension. The only method to halt the engine is with 'call' and even with the sleep or waituntil command the engine may continue but the original script is waiting for that function to finish, thus the original Script is still halted. However, execVM and spawn do not halt any code so anything is run parallel.

Here is the method implemented:

<ul>[*] a script called caller.sqf:

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

_i=0;

while {_i < 10} do {_i=_i+1;[] call counter};

hint format ["%1",Global_Var]

[*] a preprocessed counter.sqf:

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

_i=0;

while {_i<10} do {sleep 0.1;Global_Var=Global_Var+1;_i=_i+1};

_i

[*] Global_Var set to 0 in the init.sqf

Executing caller.sqf returns 100 in the hint when counter.sqf is executed with the call command, regardless of whether sleep is used. With ExecVM and spawn, 0 is returned.

Share this post


Link to post
Share on other sites

Seriously, the biki is getting me really pissed off.

twice now I've lost pages of material when editing. I guess I am going to have to go one step further and use notepad ahead of time.

This is why Web-based office document editing will never take off...

Anyways, expect some detailed information and some diagrams by tomorrow on the biki. I have to rewrite a few pages because seperating the topics into scripts vs functions is bad. It should have been SQS vs SQF and discuss scripts/functions within each - not that anyone could have known back then.

Share this post


Link to post
Share on other sites

keep up CD smile_o.gif

the internet will "never" work without notepad whistle.gif

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  

×