Jump to content
Sign in to follow this  
demonized

ready functions with call compile on 2000+ line script?

Recommended Posts

Regarding performance on MP missions, and SP aswell if it matters.

I got the idea to use this from the old UPSMON wich prepared its functions like this, i asume its of convenience to be able to acces functions from anywhere, and for time crucial things..

call compile preprocessFileLineNumbers "script.sqf";

Using the above code in init.sqf, on a script wich has alot of functions, more than 2000 lines of code.

None of my functions are really time crucial, it works fine with a few seconds delay though 10 or more seconds could have impact on some of the functions.

What i do wanted was the easy accessability, this was the reason i did this.

NOTE: My functions file is now 105 kb big and has 2593 lines, i am sure i will have more when finnished, if it ever reaches finnished state...

Now i just want to educate myself in what i really am doing with this.

1: Are there any repurcussions in having so much at the ready using the above code on large file / many functions SP or MP?

2: Would i be better of using single files for each function and just execVM or call them as needed in terms of player lag / performance?

Maybe only do it on the time crucial functions?

3: Is there any limit i should try to keep within for a MP mission?

for example only call compile preprocessFileLineNumbers "....." max 1000, 10000 lines etc, or 500 kb, 13 mb etc?

4: what is the actual purpose of doing as the code above, and is this the latest/recomended method of doing such?

Share this post


Link to post
Share on other sites

I'm really no expert on this, but...

1) Mostly memory related is my guess. A preprocess stores everything in memory making functions immediately available. I'm assuming an execVM'ed script is parsed as is (with comments and everything). I like the Domination approach, where it's separated into three different files; client, server, and common. I also prefer to separate functions that returns something via calls, functions that do something via calls, and something that do something via spawns. You may also want to separate by "thread type", like these functions will always come from a spawned process so you can use sleeps and waitUntils, while other functions are calls from main init.sqf and may not include these commands. For many things however, fsm has been reported to be a better approach than scripts.

2) I think it's just a matter of style. Assigning to handles in a single file or assigning multiple files to handles, all up to you. I'd have a hard time navigating that much data in one file. I prefer to execVM during development, as it allows re-execution while a mission is actually running. Remember to give it a global handle so you can terminate it via Gaia's debug tool, and restart it after editing. Functions or scripts/fsms, depends on how I intend to use it. If it's a one timer, why make a function of it? For time crucial stuff, consider Domination's "per frame handler", but I haven't looked much into it.

I believe coding style has a greater impact on performance (which I have my own sins). Like, having a script going for each AI or group of AI n some cases, is not recommended (yay, me, lol). It's better to have a single script/fsm (not a real) thread loop over what you need sequentially.

For bigger data arrays, like custom compositions, sound assignments across the whole island, unitplay and similar, I tend to store these in their own files. If they are one timers, just nil the variable it is stored in after use.

3) Have no idea, but Xeno makes heavy use of macros and preprocessor commands for I assume storage reasons, but at some cost on readability. Macros makes the sent mission file size smaller since it's "assembled" on the client to its working form. Preprocessor commands, if making a very flexible mission system, allows you to include all options to the same file, but at the cost of messing up line numbers on error reports. You could of course use normal if then else structures, but then it requires that additional memory to store it rather than just get rid of it during preprocess.

4) You strip off any comments and whitespaces and stores everything just as a big long messy string (I think, bah, I need some sleep). We would have problems reading that, but the interpreter copes just fine, so it's just about storage efficiency (maybe some performance, unsure, haven't tested). It's the latest one I use and know about, although I do some as fsms.

Edited by CarlGustaffa

Share this post


Link to post
Share on other sites

a) it is a design choice. some people prefer one function per file, while others prefer one file with multiple inside

b) it certainly makes sense to group functions (like client, server, both) (and for type)

c) read about execVM/spawn/call in the BIKI and here

Share this post


Link to post
Share on other sites

tnx for the input CG.

All the functions are to be reused multiple times in the mission, so functions is "neccesary".

In the early stage of this script i used if ("string" in _this) then do stuff, and just execVMéd the same file again with other strings in the passed array for various needed purposes to acess other sections of it.

This worked fine, again because my script does it stuff while the units do what the first part told them to, calculating on the fly so to speak, no time criticals.

I have been looking barely into fsm´s but never got really around to fire up the fsm editor yet, but im thinking more and more about it.

Im just a little scared and maybe not fully willing to learn a new language just yet....

Yes, the xeno/domination approach with client, sever etc files does sound like a good one, and lets face it, his mission rules public MP :)

Though most of it, 99% is serverside only, in my script.

I must admit, having all of the functions in one big file is the reason why ive spent so long on it, i think it was just me being overly neat, having absolute minimum of files for users to worry about.

But result was after some time away from the script, its sheer mass made it very hard to pick up again, especially since it was created in a period where i learned alot of new stuff, and some/many errors/bad ways i used to do had been replaced with proper or better knowledge.

I tried even at the beginning to make scripts work for multiples instead of singles, and have improved that vastly aswell in later months.

Iterating over all groups and then iterate over their members if needed all in one big go, sacrifising pinpoint time precision for long time durability with low impact for large amount of variables.

deffinitive results, no doubt.

For the 4th part you describe, thats very interesting, because i used alot of comments along the way to keep myself informed, and for others to see it aswell if desired.

I probably have a couple of hundred lines just in comments, not saying 500, but not saying not 500 either :D

Knowing they are "removed" runtime is nice by doing this is somewhat comforting.

I also prefer to separate functions that returns something via calls, functions that do something via calls, and something that do something via spawns.

This is something i really will take to heart, that would ease up alot on the confusion ive been giving myself.

@PvPscene

a: I was definetly in the camp where all gathered in one place seemed better at the time.

b: Most of my script happens on server side only, as its AI focused, though in other scripts that is something i will also take to hearth, deffinetly.

c: Tnx for those links.

I have been in and around the BIKI one and more, should probably add to the more there.

The 6th sense one looks really good.

Will be a good read.

cheers.

Edited by Demonized

Share this post


Link to post
Share on other sites

Certainly pre compile all your functions is the best way to go, regardless if it's in 1 file or in a lot more.

Only use execVM on single use/run scripts. Use call (preferred) or spawn (only when absolutely needed) on compiled code (compile preProcessFileLineNumbers), preferably stored in a global variable.

Format difference is:

functionName = { _a = _this select 0; _b = _this select 1; _a + _b };

vs

functionName = compile preProcessFileLineNumbers "functionName.sqf";

Edited by Sickboy

Share this post


Link to post
Share on other sites
Certainly pre compile all your functions is the best way to go, regardless if it's in 1 file or in a lot more.

Thats comforting to hear, and i just realized you were the author of the 6th sense page.

That had some good read in it, covering ALOT of some things ive been wondering about lately.

Share this post


Link to post
Share on other sites

It all depends on how you want to use the script. Depending on the complexity, I typically package up my functions most of the time. They have an exitWith at the top to make sure time is only spent initializing once.

I would probably split that 2000 lines file into several files for readability and package them into a directory instead, of relying on one huge single file.

About macro usage, I think readability is very much in your hands. I somehow have trouble remembering what __ccpfln(path) does in domi without thinking of what the letters mean. I have no problems remembering what __CallFile(path) does though.

One macro I've been using more lately for my packages of script is:

#define TAG(X_NAME) MF_LHD_##X_NAME

So I don't have to write the prefix all the time, and it can more easily be changed - like GVAR.

Tag(Func_A) = {...};

I'm not sure about how understandable other people will find it though.

And yes the 6-th sense page is awesome.

Share this post


Link to post
Share on other sites

Thanks guys :)

Re macros - im personally a big fan of them.

Regardless of the fact that it obscures the code somewhat - proper named macros help with that, besides, you can parse the files and evaluate the macros, so you get a preProcessed version of the script without macros. E.g sbsmac's Squint tool can do that.

CBA, ACE and SIX mods are built completely with them :)

An overview of CBA macros is available at http://dev-heaven.net/docs/cba/files/main/script_macros_common-hpp.html

I suppose the CBA source could be a good example (included with the releases, or available on the repo http://dev-heaven.net/projects/cca/repository).

Edited by Sickboy

Share this post


Link to post
Share on other sites

There is also other situations where is "good" to have functions, for example:

(findDisplay 46) displayAddEventHandler ["KeyDown", "_this call MY_function"];

This will help you have a cleaner code, like:

_trigger setTriggerStatements ["this", "_this call MY_function", ""];

Instead of having big number of strings

_trigger setTriggerStatements ["this", 
"
  hint ""Some text"";
  [] execVM ""SomeScript.sqf"";
  ... more code ...
", ""];

_neo_

Share this post


Link to post
Share on other sites

Macros are a big no no.

Use IDEs available nowadays for code completion and code templates. :P

Share this post


Link to post
Share on other sites
Macros are a big no no.

Use IDEs available nowadays for code completion and code templates. :P

In a game with a limited scripting language and config file system like SQF/CPP in the ArmA series, Macros are a big yes yes, combination with IDEs for code completion and code templates is great too.

Besides these IDE's should be able to process the macros (like squint), giving you best of both worlds.

For CBA/ACE etc, macros provide central definitions, portability of components, and no need to have regard for global component namespaces, amongst many other things.

Compared to script functions, macros are processed only during preProcessing of the script files, while with scripting every call made requires cpu cycles :) So IMO it makes sense to use them in certain situations over script functions.

Lastly, as pointed out before, the source files, once preProcessed, are rid of macros and only contain static text, so you have always the ability to review/copy/edit files as the game will process them.

Edited by Sickboy

Share this post


Link to post
Share on other sites

Sickboy - I can see that the primary point of script_macros_common.hpp is to help addon makers. I know everything won't work in scripts due to missing certain defines like component, but PARAMS_N and EXPLODE and the debug macros might be very useful. It it also usable/advicable to use in scripts?

Share this post


Link to post
Share on other sites
Sickboy - I can see that the primary point of script_macros_common.hpp is to help addon makers. I know everything won't work in scripts due to missing certain defines like component, but PARAMS_N and EXPLODE and the debug macros might be very useful. It it also usable/advicable to use in scripts?
Actually the same include files are used for scripts and configs alike.

Per Mod: Global Mod defines

Per Component: Component defines

Configs and scripts only include the component-file (which in turn includse the mod file, and the macros file).

Example config.cpp

Example function

Example init script

Edited by Sickboy

Share this post


Link to post
Share on other sites

Macros in most cases make scripts a lot harder to read.

Readability is one of the most important parts of code.

Way more important than coding speed.

Defines, ifdef and all that are no macros.

Share this post


Link to post
Share on other sites

I'm sorry I meant scripts in missions, not in addons.

What do you do with PREFIX and COMPONENT in a script in a mission?

Share this post


Link to post
Share on other sites
Macros in most cases make scripts a lot harder to read.

Readability is one of the most important parts of code.

Way more important than coding speed.

Defines, ifdef and all that are no macros.

As said, readability is no problem because you can let tools like Squint preProcess the files (and hopefully your IDE too).

Same you do with configs -> rap -> unrap -> readable, or dump the ingame memory config to AllInOneConfig.

Admittedly, the macros are more intended to improve development than readability (for those unfamilair with the macros).

TBH I have often considered 'binarizing' script files (preprocessing in this case) when pbo-ing for release, but never got around to it.

Defines/Ifdefs/etc and macros are IMO rather related and both introduce a level of obscurity unless preProcessed.

Perhaps macros have been more widely accepted for configs, but I personally see little difference, especially with the 'preProcess' capabilities available for both configs and scripts.

Putting everything in functions can also be seen as a sort of obscurity, yet clearly more acceptable.

Descriptive naming goes a long way in all cases.

If the scripting engine / config definitions would get to the level of languages like Python or Ruby (both don't even have possibilities for defines/macros afaik), which has a lot more syntactic sugar and meta programming etc, then the arguments IMO make sense against Macros etc.

I'm sorry I meant scripts in missions, not in addons.

What do you do with PREFIX and COMPONENT in a script in a mission?

Namespaces. They count just as well for scripting as they do for configs.

Surely less for missions than for addons (which we primarily make), but if I'd design a mission it would be with the same namespace rules anyway.

#define PREFIX ACE
#define COMPONENT sys_wounds

GVAR(enabled) = false; // ACE_sys_wounds_enabled = false;

Edited by Sickboy

Share this post


Link to post
Share on other sites

So if I make a script_component.hpp like this:

//FILE: MF_Mission\script_component.hpp

#define PREFIX MF
#define COMPONENT Mission

//Must define debug level before include
#define DEBUG_MODE_FULL

#include "\x\cba\addons\main\script_macros_common.hpp"
//Or this??
//#include "x\cba\addons\main\script_macros.hpp"

Then I just include it and I can use debug macros and everything in macros_common? Which of these 2 includes should I use in a mission?

Thanks.

Sorry for going of topic Demonized.

Share this post


Link to post
Share on other sites

script_macros.hpp is intended for specific macros for CBA mod (empty currently), unless you want to use them, including script_macros_common should do.

Re the debug mode - you could leave it commented out, and also add it commented out to the top of script files. This way you can enable the debug for the whole component at once, or per script file (or like in CBA/ACE, make a list of commented out defines per component or even script file, centrally located in script_component / script_mod etc, and then use #ifdef in the various script files).

On a side note; If you intend several components in your missions, you could put script_mod.hpp in the root, and use a folder per component, and a script_component.hpp inside of each folder.

There are some limitations with #include that make the usage of them harder in missions - including files from the same folder level, or from subfolders is easy, but from parent folders etc would require an absolute path. For missions that's something like \missions\__cur_sp.island and \missions\__cur_mp.island

See http://forums.bistudio.com/showthread.php?t=123397

Edited by Sickboy

Share this post


Link to post
Share on other sites

I use the CBA functions a lot. However, i'm still not sure whether to actually use CBA macros instead of custom macros. There are some very useful ones like GVAR and FUNC, however, I can't use the accompanying PREP. And some minor differences regarding the presense of an ending semicolon in the macros. They do make quite a bit of things easier though.

Share this post


Link to post
Share on other sites

Using PREP should be possible, because we left out the leading \. That means you can build the folder structure inside your mission, and it will work.

However you can simply override / supplement as you see fit :)

Perhaps we could even add a mission include file in CBA, which repurposes some of the macros better for missions - we'll gladly accept code donations :)

Edited by Sickboy

Share this post


Link to post
Share on other sites
Using PREP should be possible, because we left out the leading \. That means you can build the folder structure inside your mission, and it will work.

However you can simply override / supplement as you see fit :)

Perhaps we could even add a mission include file in CBA, which repurposes some of the macros better for missions - we'll gladly accept code donations :)

Well then I'll get right on it :).

Share this post


Link to post
Share on other sites

Not everything have to be addonless especially not a <5MB addon which everybody should use anyway.

I made something which should do it. How to deliver ? You can PM me in here.

Edited by Muzzleflash

Share this post


Link to post
Share on other sites
Sorry for going of topic Demonized.

No worries, interesting read, have been wondering abit about the macros stuff as well.

I personally like the fact that "everyone" can read the codes, but since ive gotten deeper into scripting i have been more focused upon the actual result rather than readability.

Learned alot from this thread.

Cheers all.

Share this post


Link to post
Share on other sites

Remember the wise words of Spooner regarding macros.

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  

×