Jump to content
Sign in to follow this  
Guest

We need "exec"

Recommended Posts

Guest

One of the major limitations of the OFP script language is that it doesn't allow user defined functions that return values. This makes any more serious script writing a real pain.

Using global variables to transfer values between two scripts dosn't cut it since the script language interpretation is in real-time. If several instances of the same script are running simultaneously then there will be a resource conflict over the global vars it is using. We can therefor rule out using global variables for return values from scripts.

I think that most scripters would agree that a modification of the exec function would be very, very welcome and desired.

Currently, there is one solution. It is not a good one, but it is a solution. The limitation of it is that you can only use the functionallity within the script that it is defined. It looks something like this (this is just for illustrations, I havn't checked the code in detail, so there might be errors, but you'll get the idea):

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

_a = 3

_b = 2

_c = 1

; Call first function

_aSumTwoValues = +_a

_bSumTwoValues = +_b

_returnLabelSumTwoValues  = "AfterSum"

goto "SumTwoValues"

#AfterSum

_result = +_resultSumTwoValues

; Call second function

_aSubtractTwoValues= +_result

_bSubtractTwoValues = +_c

_returnLabelSubtractTwoValues =  "AfterSubtraction"

goto "SubtractTwoValues"

#AfterSubtraction

_result2 = +_returnSubtractTwoValues

; end function calls

; now we have that _result2 = (a+b)-c

exit

; Function 1: A + B

#SumTwoValues

 _returnSumTwoValues = _aSumTwoValues + _bSumTwoValues

goto _returnLabelSumTwoValues

; function 2: A-B

#SubtractTwoValues

 _returnSubtractTwoValues = _aSubtractTwoValues + _SubtractTwoValues

goto _returnLabelSubtractTwoValues

<span id='postcolor'>

This works in principle, but it is extremely clumsy and it requires the abuse of numerous local variables sad.gif

What would be desirable would be:

Main script: main.sqs

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

_a = 3

_b = 2

_c = 1

_res = [_a,_b] exec "sum.sqs"

_res2 = [_res,_c] exec "subtract.sqs"

<span id='postcolor'>

Sum.sqs:

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

return (this select 0) + (this select 1)

<span id='postcolor'>

Subtract.sqs:

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

return (this select 0) - (this select 1)

<span id='postcolor'>

Share this post


Link to post
Share on other sites

You might try to work with a global list and a global index to this list. Each time you call a subroutine you give it the current value of the index, store the index in a local variable of the calling routine and increment it afterward. The subroutine stores the result at the index position of the global list and the calling routine can read it with its local copy of the index.

The list must be big enough to handle all concurrent function calls. If none of the called routines is time consuming (eg. waiting for a trigger) you can also make it circular (if the index comes to the end of the list it starts with 0 again) to save memory.

Just an idea, never tried it  wink.gif

(and of course, return values would be easier smile.gif

Edit: You might need another one or two global boolean lists, to indicate when the subroutine has written the result and whether the result has been read by the calling routine.

With all this you might even try to make a slot handler, where other scripts get assigned unused result slots to optimize memory usage.

Share this post


Link to post
Share on other sites
Guest

Yes, that was my first idea too actually. The problem is however that you would need one such global list and global index per script (in addition to a local index variable per call to the function so you know where to get your value). I am terrified of global variables in OFP since I am pretty sure that it doesn't have any real-time safeguards and that there could be severe timing and resource sharing conflicts.

Example situation:

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

globalIndex = 0

; call function 1

globalIndex = globalIndex + 1

_myLocalIndex = globalIndex

; call function 2

globalIndex = globalIndex + 1

_myLocalIndex = globalIndex

<span id='postcolor'>

Now imagine how this could look like

if somebody called function 1 and 2 simultaneously:

Order of execution:

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

1) globalIndex = globalIndex + 1; function 1

2) globalIndex = globalIndex + 1; function 2

3) _myLocalIndex = globalIndex; function1

4) _myLocalIndex = globalIndex;function 2

<span id='postcolor'>

Instead of getting _myLocalIndex to be 1 for the first call and

2 for the second we get that they are equal to 2 in both cases; the call for function1 will be getting function 2's values.

Share this post


Link to post
Share on other sites

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (denoir @ Aug. 08 2002,15:53)</td></tr><tr><td id="QUOTE">I think that most scripters would agree that a modification of the exec function would be very, very welcome and desired.<span id='postcolor'>

Unfortunatelly the thing you suggest cannot be accompished via any modification of "exec". Exec spawns parallel execution of another script and returns immediatelly - therefore reliably returing value from it is not possible.

We are aware this is serious limitation of the scripting language - but I am afraid you will have to live with it as it, as it is very unlikely that any OFP patches will make any fundamental changes like this.

Share this post


Link to post
Share on other sites

I don't think that "exec" must be changed, but I would like to see a "function"-possibility implemented, that you could do something like this:

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

: myfunction

_params = _this

_a = _this select 0

_b = _this select 1

_result = _a + _b

return _result

<span id='postcolor'>

It's just like programming a function in C/C++ or Pascal a.s.o. Then you could invoke this function into a script with something like this:

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

include "myfunction.sqs"

<span id='postcolor'>

But I don't know if this would be hard to implement.

Share this post


Link to post
Share on other sites

But this is exactly what denoir asked for, a return value that could be used in the calling routine.

@denoir: yepp, multithreading is a killer for this approach and the scripts might be most likely handled in this way.

A way around this would be a central slot handler routine, but this is not easy to implement as well...

Share this post


Link to post
Share on other sites
Guest

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote </td></tr><tr><td id="QUOTE">

We are aware this is serious limitation of the scripting language - but I am afraid you will have to live with it as it, as it is very unlikely that any OFP patches will make any fundamental changes like this.

<span id='postcolor'>

Well, then it is going to be on the top of my wish list for OFP2 wink.gif

Actually, I was too pessimistic about the global list solution. I did an experiment with 15 simultaneous executions and there was no synchronization problem. The principle I used is the follwing (credit and thanks goes to Spinor for the code):

This is to initialize the system, e.g. in the init.sqs:

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

;initialization-----------------------------

sCurrentID = 0

sIDStack = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]

sResultStack = []; sResultStack ReSize 16

;-------------------------------------------

<span id='postcolor'>

This is the calling routine. The only line that has to be customized is the exec command. <arguments> are any parameters you pass to the function. The additional argument _ID is necessary. It stores the functions ID number (as refering to the stacks):

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

;call routine---------------------------------

sCurrentID = (sCurrentID + 1) Mod 16; _ID = sCurrentID; sIDStack Set [_ID, true]

[...<arguments>...,_ID] exec "<subscript>.sqs"

@!(sIDStack select _ID)

_result = sResultStack select _ID

;-------------------------------------------

<span id='postcolor'>

This is the return routine in the function script. It simply writes the result in rResultStack and notifies the calling script that its finished:

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

;return routine-----------------------------

;don't forget to define _ID and _result !!!

sResultStack Set [_ID, _result]

sIDStack Set [_ID, false]

;-------------------------------------------

<span id='postcolor'>

Share this post


Link to post
Share on other sites

@denoir:

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote </td></tr><tr><td id="QUOTE">I did an experiment with 15 simultaneous executions and there was no synchronization problem.<span id='postcolor'>

after you told me about possible problems with a global stack I did exactly the same wink.gif

@Suma

Could you explain how simultaneous scripts are executed? E.g. is there a command interpreter for each script that runs independently from the others or is there one command interpreter into which the commands from all scripts are fed alternately?

If the latter is true, what blocks are fed into the interpreter?

E.g. for the above system presented by denoir to run safely it would be necessary that a line of code from one script is executed in one go.

Share this post


Link to post
Share on other sites

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Spinor @ Aug. 09 2002,15:06)</td></tr><tr><td id="QUOTE">Could you explain how simultaneous scripts are executed? E.g. is there a command interpreter for each script that runs independently from the others or is there one command interpreter into which the commands from all scripts are fed alternately?<span id='postcolor'>

There is one command interpreter.

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote </td></tr><tr><td id="QUOTE">If the latter is true, what blocks are fed into the interpreter?<span id='postcolor'>

Atomic execution block is:

until you use any wait condition (&, @, ~)

or

until 100 lines is executed (this is to avoid lockups caused by infinite loops).

If your script is never using "goto" backwards or wait instructions and if it is shorted than 100 lines, it can be considered atomic.

Share this post


Link to post
Share on other sites

Like Suma said, that's not a small mod to the exec function.

You can not treat scripts as functions in the current implementation.

Good idea though with the stack, you can also resize the stack every time you increase the ID count I think. So it would make it fully dynamic.

smile.gif

Share this post


Link to post
Share on other sites

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Suma @ Aug. 09 2002,16:28)</td></tr><tr><td id="QUOTE">until you use any wait condition (&, @, ~)<span id='postcolor'>

Sorry for going a bit offtopic, but what is the difference between these three?

Share this post


Link to post
Share on other sites

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Kegetys @ Aug. 09 2002,09:36)</td></tr><tr><td id="QUOTE"></span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Suma @ Aug. 09 2002,16:28)</td></tr><tr><td id="QUOTE">until you use any wait condition (&, @, ~)<span id='postcolor'>

Sorry for going a bit offtopic, but what is the difference between these three?<span id='postcolor'>

~<float> lets you pause for <float> seconds

@<condition> waits for <contidion> to = ture

&<float> waits for <float> = DayTime

Share this post


Link to post
Share on other sites
Guest

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Suma @ Aug. 09 2002,15:28)</td></tr><tr><td id="QUOTE">Atomic execution block is:

until you use any wait condition (&, @, ~)

or

until 100 lines is executed (this is to avoid lockups caused by infinite loops).

If your script is never using "goto" backwards or wait instructions and if it is shorted than 100 lines, it can be considered atomic.<span id='postcolor'>

Great. Thanks Suma smile.gif

So to conclude then: global lists will work fine as long as you don't mess with the indexing variables after 100 lines after the call of the function.

That is very good. Now I can reduce my matrix manipulation code by at least 80% smile.gif

Share this post


Link to post
Share on other sites

I just saw this old post and thought it was cool that BIS did put in functions.

So cool they listen like that. Glad you guys asked for it too.

Doolittle

Share this post


Link to post
Share on other sites

We have still function ??

plus.sqf

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">private{_a,_b};

_a = _this select 0;

_b = _this select 2;

_a + _b<span id='postcolor'>

We can use like it :

</span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">plus = loadfile "plus.sqf"

_a = 10

_b = 5

_c = [_a,_b] call plus<span id='postcolor'>

My code works and I imagine that my parameter is putting in a stack ?

What is the problem ?

Maybe i don't understand a technicality ?

Share this post


Link to post
Share on other sites

Oh  !!! I don't read the date of this post ....

Perhaps can you answer a little question :

I have make a function which use _count {private _count}

_count is'nt passed in parameter

but i call this function in a loop which use _count (to loop), and the function modify the _count in the loop, why? what's wrong in my function ?

PS: thx Denoir & BIS for the call function

Share this post


Link to post
Share on other sites
Guest

There is really no point in digging up such an old thread.

MaxPower - post your question in a new thread, and if I may suggest post a little more detailed explanation of your problem, I'm not sure that I quite get what you want to do.

Closing smile.gif

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

×