Jump to content
killzone_kid

[FEEDBACK] Do you use BIS_fnc_xxxxx functions? If you do....

Recommended Posts

I am wanting more than 1 plane at a time to be in the air, or working the pattern, or landing and taking off, at a time. Visiting multiple airports sleeping for a few minutes then moving to the next. I have figured it out with helos, but planes are different and difficult, due to the runways, ILS positions, and taxi positions. Landat is not always success, and waypoints are not perfect. ambflyby is great for flybys, but I want true ambient aircraft.

 

thanks for the suggestion.

 

 

 

Rather than trying to use the fsm directly, why not use a function such as BIS_fns_ambientFlyBy?

ambFlyby = [getmarkerpos "startMarker", getmarkerpos "stopMarker", 100, "FULL", "B_Plane_CAS_01_F", WEST] call BIS_fnc_ambientFlyBy;

Share this post


Link to post
Share on other sites

Where do I place this bit of ode to call the ambient flyby and how can I make it repeat?

 

Rather than trying to use the fsm directly, why not use a function such as BIS_fns_ambientFlyBy?

ambFlyby = [getmarkerpos "startMarker", getmarkerpos "stopMarker", 100, "FULL", "B_Plane_CAS_01_F", WEST] call BIS_fnc_ambientFlyBy;

Share this post


Link to post
Share on other sites

BIS_fnc_drawMinefields could use the newer allMines command, instead of shifting through allMissionObjects.

Share this post


Link to post
Share on other sites

I humbly suggest to update BIS_fnc_selectRandomWeighted with this:

/*
    Author: Joris-Jan van 't Land, optimized by Karel Moricky, modified by Grumpy Old Man

    Description:
    Function to select a random item from an array, taking into account item weights.
    The weights should be Numbers between 0 and 1, with a maximum precision of hundreds.

    Parameter(s):
    _this select 0: source Array (Array of Any Value)
    _this select 1: weights (Array of Numbers)

    Returns:
    Any Value selected item

    Example:

    [["apples","bananas","tractor"],[0.5,0.25,0.25]] call BIS_fnc_selectRandomWeighted

    TODO:
    [*] Algorithm is inefficient?
*/



params [["_array",[]],["_weights",[]]];

if !((count _array) isEqualTo (count _weights)) exitWith {"There must be at least as many elements in Weights (1) as there are in Array (0)!" call bis_fnc_error; nil};



_weightsTotal = 0;
{
    _x = _x param [0,0,[0]];
    _weightsTotal = _weightsTotal + _x;
} count _weights;

_weightCheck = _weightsTotal isEqualTo 0;
_return = [];
if (!_weightCheck) then {

    private ["_weighted"];
    _weighted = [];
    {
        private ["_weight"];
        _weight = _x / _weightsTotal;

        _weight = round (_weight * 100);

        for "_k" from 1 to _weight do
        {
            _weighted pushback _foreachindex;
        };
    } foreach _weights;

    private ["_index"];
    _index = selectRandom _weighted;

    _return = _array select _index;
};

if (_weightCheck) then {

    ["The sum of weights must be larger than 0"] call bis_fnc_error;
    nil

};
_return

Using this:

[["apples","bananas","tractor"],[0.5,0.25,0.25]] call BIS_fnc_selectRandomWeighted

the original one runs at 0.237079 ms, my modified version runs at 0.0995 ms.

Replaced the foreach loop with count, added isEqualTo checks, pushBack and replaced the "from 0 to _weighted -1" with "from 1 to _weighted".

No idea how to squeeze more performance out of it other than taking a whole different approach, the current speed gain is impressive enough for me.

 

Results for 100.000 iterations:

 

Original one:

[["tractor",24870],["apples",50116],["bananas",25014]] //23.589s

My modification:

[["bananas",24779],["apples",49939],["tractor",25282]] //10.005s

Cheers

  • Like 4

Share this post


Link to post
Share on other sites

Even more humbly I suggest this (with a bit of algorithmical improvement):

/*
    Author: Joris-Jan van 't Land, optimized by Karel Moricky, modified by Grumpy Old Man, a bit more optimized by pedeathtrian

    Description:
    Function to select a random item from an array, taking into account item weights.
    The weights should be Numbers between 0 and 1, with a maximum precision of hundreds.

    Parameter(s):
    _this select 0: source Array (Array of Any Value)
    _this select 1: weights (Array of Numbers)

    Returns:
    Any Value selected item

    Example:

    [["apples","bananas","tractor"],[0.5,0.25,0.25]] call BIS_fnc_selectRandomWeighted

    TODO:
    [*] Algorithm is inefficient?
*/
params [["_array",[]],["_weights",[]]];
if !((count _array) isEqualTo (count _weights)) exitWith {"There must be at least as many elements in Weights (1) as there are in Array (0)!" call BIS_fnc_error; nil};

_weightsTotal = 0;
_wCheckFail = false;
{
	_x = _x param [0,0,[0]];
	if (_x < 0) exitWith {_wCheckFail = true};
	_weightsTotal = _weightsTotal + _x;
} count _weights;
if (_wCheckFail) exitWith {"Non-negative weights expected!" call BIS_fnc_error; nil};

if (_weightsTotal isEqualTo 0) exitWith {"The sum of weights must be larger than 0" call BIS_fnc_error; nil};
_return = [];
_wCheckFail = true;
_rnd = random _weightsTotal;
{
	if (_rnd < _x) exitWith {_wCheckFail = false; _return = _array select _forEachIndex};
	_rnd = _rnd - _x;
} forEach _weights;
_return

Or, alternatively, this (uses slightly different approach and binary search (could win on large arrays))

/*
    Author: Joris-Jan van 't Land, optimized by Karel Moricky, modified by Grumpy Old Man, a bit more optimized by pedeathtrian

    Description:
    Function to select a random item from an array, taking into account item weights.
    The weights should be Numbers between 0 and 1, with a maximum precision of hundreds.

    Parameter(s):
    _this select 0: source Array (Array of Any Value)
    _this select 1: weights (Array of Numbers)

    Returns:
    Any Value selected item

    Example:

    [["apples","bananas","tractor"],[0.5,0.25,0.25]] call BIS_fnc_selectRandomWeighted

    TODO:
    [*] Algorithm is inefficient?
*/
params [["_array",[]],["_weights",[]]];
_cnt = count _array;
if !(_cnt isEqualTo (count _weights)) exitWith {"There must be at least as many elements in Weights (1) as there are in Array (0)!" call BIS_fnc_error; nil};

_weightsTotal = 0;
_weightsCumulative = [];
_wCheckFail = false;
{
	_x = _x param [0,0,[0]];
	if (_x < 0) exitWith {_wCheckFail = true};
	_weightsTotal = _weightsTotal + _x;
	_weightsCumulative pushBack _weightsTotal;
} count _weights;
if (_wCheckFail) exitWith {"Non-negative weights expected!" call BIS_fnc_error; nil};

if (_weightsTotal isEqualTo 0) exitWith {"The sum of weights must be larger than 0" call BIS_fnc_error; nil};
_rnd = random _weightsTotal;
_min = 0;
while {(_cnt-_min) > 1} do {
	private _mid = floor ((_cnt+_min)/2);
	private _midW = _weightsCumulative select _mid;
	if (_rnd < _midW) then {
		_cnt = _mid;
	} else {
		_min = _mid
	};
};
_array select _cnt
 


My stats of processing same input: 100000 calls (all ordered for ["apples","bananas","tractor"]):

Original:

[50079,24896,25025] // 34.3989 sec; avg 0.000343989

Grumpy Old Man's version:

[50399,24966,24635] // 14.572 sec; avg 0.00014572"

(as you can see my machine is slower, but ratio is kept the same).

 

My version 1:

[50021,25117,24862] // 3.66309 sec; avg 3.66309e-005

My version 2 (with bin. search; makes almost no difference to previous due to very short array):

[50116,25032,24852] // 3.66199 sec; avg 3.66199e-005


I also decided if check input weights, then they should all be non-negative.

 

UPD. Also, in my version you're freed from limitation "weights should be Numbers between 0 and 1, with a maximum precision of hundreds", they just should be non-negative (and preferably not causing sum overflow; and not sum to zero)

  • Like 1

Share this post


Link to post
Share on other sites

Your first example runs for 0.0247 ms here, very nice.

The second one throws an error in the line "_weightsCumulative pushBack _weightsTotal;" because count expects bool, add a true there and you're set.

Second one runs 0.0311 ms with the bool error fixed.

 

Very impressive.

 

Cheers

Share this post


Link to post
Share on other sites

Looks like KK added his own version of BIS_fnc_selectRandomWeighted to the devbranch, running at 0.0275 ms.

Thanks for the improvement!

 

Cheers

Share this post


Link to post
Share on other sites

Not exactly a function I use in that sense but one that is triggered through the ORBAT group module. When sync'ing the module to a unit, the ORBAT icon will follow it on the map. However, this also overwrites the given groupID with the content of the "text" attribute in the ORBAT entry. (Note that it is the "text" attribute, not the "textShort" one which would make much more sense IMO.) Untested suggestion to fix it, two altered lines marked in red: Grr, it overwrites my text formatting. Altered lines are 27 and 40.

 

BIS_fnc_moduleStrategicMapORBAT

 

_logic = _this param [0,objnull,[objnull]];
_units = _this param [1,[],[[]]];
_activated = _this param [2,true,[true]];

if (_activated) then {
	_pos = position _logic;
	_class = call compile (_logic getvariable "Path");
	_parent = call compile (_logic getvariable "Parent");
	_tags = _logic getvariable ["Tags",""];
	_tiers = (call compile (_logic getvariable "Tiers")) call bis_fnc_parsenumber;

	if (isnil "_class") then {_class = configfile;};
	if (isnil "_parent") then {_parent = _class;};
	if (isnil "_tiers") then {_tiers = -1;};

	_class = _class param [0,configfile,[configfile]];
	_parent = _parent param [0,configfile,[configfile]];
	_tags = call compile ("[" + _tags + "]");

	_logic setvariable ["data",[_pos,_class,_parent,_tags,_tiers]];

	//--- No Strategic Map connected - display in the main map
	if ({typeof _x == "ModuleStrategicMapInit_F"} count (synchronizedobjects _logic) == 0) then {

		_classParams = _class call bis_fnc_ORBATGetGroupParams;
		_text = _classParams select ("text" call bis_fnc_ORBATGetGroupParams);
		_textshort = _classParams select ("textshort" call bis_fnc_ORBATGetGroupParams);
		_texture = _classParams select ("texture" call bis_fnc_ORBATGetGroupParams);
		_size = _classParams select ("size" call bis_fnc_ORBATGetGroupParams);
		_sizeTexture = _classParams select ("sizeTexture" call bis_fnc_ORBATGetGroupParams);
		_textureSize = _classParams select ("textureSize" call bis_fnc_ORBATGetGroupParams);
		_color = _classParams select ("color" call bis_fnc_ORBATGetGroupParams);
		_iconSize = sqrt (_size + 1) * 26;

		//--- Assign the icon to a group
		if (count _units > 0) then {
			private ["_grp"];
			_grp = group (_units select 0);
			if !(isnull _grp) then {
			        _grp setgroupid [_textshort]; // Either this, or remove line entirely.
				_pos = [_grp];
			};
		};

		_iconParams = [_texture,_color,_pos,_iconSize * _textureSize,_iconSize * _textureSize,0,"",false];
		_sizeIconParams = if (_size >= 0) then {[_sizetexture,_color,_pos,_iconSize,_iconSize,0,"",false]} else {[]};

		//--- Register icons
		_drawIcon = missionnamespace getvariable ["BIS_fnc_moduleStrategicMapORBAT_drawIcon",[]];
		_drawIcon set [count _drawIcon,[_class,[_parent,_tags,_tiers],_iconParams,_classParams,_sizeIconParams]];
		missionnamespace setvariable ["BIS_fnc_moduleStrategicMapORBAT_drawIcon",_drawIcon];

		//--- Register ORBAT viewer on click event
		_ORBATonClick = missionnamespace getvariable ["BIS_fnc_moduleStrategicMapORBAT_ORBATonClick",[]];
		_ORBATonClick set [count _ORBATonClick,_class];
		_ORBATonClick set [
			count _ORBATonClick,
			{
				disableserialization;
				[_this select 0,1,BIS_fnc_moduleStrategicMapORBAT_display select 0,BIS_fnc_moduleStrategicMapORBAT_drawIcon] spawn bis_fnc_strategicMapAnimate;
				true
			}
		];
		missionnamespace setvariable ["BIS_fnc_moduleStrategicMapORBAT_ORBATonClick",_ORBATonClick];
		BIS_fnc_moduleStrategicMapORBAT_mouseClickDisable = false;

		//--- Initialize UI event handlers
		if (isnil {BIS_fnc_moduleStrategicMapORBAT_draw}) then {
			disableserialization;

			BIS_fnc_moduleStrategicMapORBAT_draw = {
				_control = _this select 0;
				_mousePos = missionnamespace getvariable ["BIS_fnc_moduleStrategicMapORBAT_mousePos",[0,0]];
				_drawIcon = missionnamespace getvariable ["BIS_fnc_moduleStrategicMapORBAT_drawIcon",[]];
				_overlay = missionnamespace getvariable ["BIS_fnc_ORBATAddGroupOverlay_groups",[]];
				_selected = [];
				{
					scriptname "BIS_fnc_moduleStrategicMapORBAT_draw";
					_class = _x select 0;
					_iconParams = +(_x select 2);
					_classParams = +(_x select 3);
					_sizeIconParams = +(_x select 4);

					_pos = _iconParams select 2;
					if (count _pos == 1) then {
						_pos = visibleposition leader (_pos select 0);
						_iconParams set [2,_pos];
						_sizeIconParams set [2,_pos];
					};

					_mapPos = _control ctrlmapworldtoscreen _pos;
					_iconSize = _iconParams select 3;
					_isSelected = ((_mapPos distance _mousePos) / _iconSize) < 0.0007;
					if (_isSelected) then {
						_iconSize = _iconSize * 1.2;
						_iconParams set [3,_iconSize];
						_iconParams set [4,_iconSize];
						_selected = _x;
					};
					_control drawicon _iconParams;

					//--- Draw size texture
					if (count _sizeIconParams > 0) then {
						if (_isSelected) then {
							_sizeIconSize = (_sizeIconParams select 3) * 1.2;
							_sizeIconParams set [3,_sizeIconSize];
							_sizeIconParams set [4,_sizeIconSize];
						};
						_control drawIcon _sizeIconParams;
					};

					//--- Draw custom textures
					_classID = _overlay find _class;
					if (_classID >= 0) then {
						_classOverlay = _overlay select (_classID + 1);
						_iconColor = _iconParams select 1;
						{
							if (typename _x == typename []) then {
								_xTexture = _x select 0;
								_xColor = +(_x select 1);
								_xWidth = _x select 2;
								_xHeight = _x select 3;
								_xAngle = _x select 4;
								_xText = _x select 5;
								_xShadow = _x select 6;

								//--- Read dynamic params passed as code
								if (typename _xColor == typename {}) then {
									_xColor = call _xColor;
									_xColor = _xColor param [0,[1,1,1,1],[[]]];
								};
								if (typename _xWidth == typename {}) then {
									_xWidth = call _xWidth;
									_xWidth = _xWidth param [0,1,[1]];
								};
								if (typename _xHeight == typename {}) then {
									_xHeight = call _xHeight;
									_xHeight = _xHeight param [0,1,[1]];
								};
								if (typename _xAngle == typename {}) then {
									_xAngle = call _xAngle;
									_xAngle = _xAngle param [0,0,[0]];
								};

								_xColor set [3,(_xColor select 3) * (_iconColor select 3)];

								//--- Convert size to coeficients of original icon size
								_xWidth = _xWidth * _iconSize;
								_xHeight = _xHeight * _iconSize;

								//--- Draw
								_control drawicon [_xTexture,_xColor,[_pos select 0,_pos select 1],_xWidth,_xHeight,_xAngle,_xText,_xShadow];
							};
						} foreach _classOverlay;
					};
				} foreach _drawIcon;


				if (count _selected > 0 && !BIS_fnc_moduleStrategicMapORBAT_mouseClickDisable) then {
					_class = _selected select 0;
					_classParams = _selected select 3;
					[_classParams,ctrlparent _control,_mousePos] call bis_fnc_ORBATTooltip;
					_control ctrlMapCursor ["Track","HC_overFriendly"];
				} else {
					[[],ctrlparent _control] call bis_fnc_ORBATTooltip;
					_control ctrlMapCursor ["Track","Track"];
				};
				BIS_fnc_moduleStrategicMapORBAT_selected = _selected;
			};
			BIS_fnc_moduleStrategicMapORBAT_mouse = {
				BIS_fnc_moduleStrategicMapORBAT_mousePos = [_this select 1,_this select 2];
			};

			//--- Add event handlers
			_fnc_addHandlers = {
				{
					_x spawn {
						disableserialization;
						waituntil {!isnull (finddisplay _this displayctrl 51)};
						_control = finddisplay _this displayctrl 51;
						_control ctrladdeventhandler ["draw","_this call BIS_fnc_moduleStrategicMapORBAT_draw;"];
						_control ctrladdeventhandler ["mousemoving","_this call BIS_fnc_moduleStrategicMapORBAT_mouse;"];
						_control ctrladdeventhandler ["mouseholding","_this call BIS_fnc_moduleStrategicMapORBAT_mouse;"];
						_control ctrladdeventhandler ["mousebuttonclick","['BIS_fnc_moduleStrategicMapORBAT',_this] spawn BIS_fnc_strategicMapMouseButtonClick;"];
					};
				} foreach [
					getnumber (configfile >> "RscDisplayMainMap" >> "idd"),
					getnumber (configfile >> "RscDisplayGetReady" >> "idd"),
					getnumber (configfile >> "RscDisplayClientGetReady" >> "idd"),
					getnumber (configfile >> "RscDisplayServerGetReady" >> "idd")
				];
			};

			[] spawn _fnc_addHandlers;
			addmissioneventhandler ["loaded",_fnc_addHandlers];
		};
	};
};

 

Will also spam the FT soon.

Edit: FT Ticket - https://feedback.bistudio.com/T120008

Share this post


Link to post
Share on other sites

An easy function improvement:

 

In BIS_fnc_locationDescription the nearestLocations command uses the player position to find locations to use as a reference for the supplied position. Surely it should use the supplied position instead? (Or you could use worldSize to make sure you get every location on the map if you wanted)

  • Like 1

Share this post


Link to post
Share on other sites

An easy function improvement:

 

In BIS_fnc_locationDescription the nearestLocations command uses the player position to find locations to use as a reference for the supplied position. Surely it should use the supplied position instead? (Or you could use worldSize to make sure you get every location on the map if you wanted)

 

Good catch!

Share this post


Link to post
Share on other sites

For purely selfish reason I've always thought BIS_fnc_buildingPositions would be even better if it differentiated between inside (with a roof and enclosing walls) and outside (balconies etc)

 

Most of the time I use that function it's to place a unit inside a building, hidden in cover etc, but having them standing out on a balcony, or on a porch, or even under the roof at the petrol stations doesn't quite do the job. Sure I get why they're building positions, but it would be great to be able to exclude any that aren't enclosed. 

Share this post


Link to post
Share on other sites

Please take a look into BIS_fnc_enemyTargets and BIS_fnc_enemyDetected.

 

BIS_fnc_enemyTargets:

/*
    Author: Jiri Wainar

    Description:
    Return list of nearby enemy targets for given unit.

    Parameter(s):
    _this: unit that is inspected

    Returns:
    _targets:array (empty array if unit doesn't know about any enemy)

    Example:
    _targets:array = _unit call BIS_fnc_enemyTargets;
    _targets:array = [_unit(,_distance)] call BIS_fnc_enemyTargets;
*/

private["_pivot","_distance","_targets","_enemies","_enemySides","_side","_unit"];

_pivot    = _this param [0,objNull,[objNull]];
_distance = _this param [1,300,[123]];

_targets  = _pivot nearTargets _distance;

_enemies = [];

_enemySides = _pivot call BIS_fnc_enemySides;

{
    _unit = (_x select 4);
    _side = (_x select 2);

    if ((_side in _enemySides) && (count crew _unit > 0)) then
    {
        if ((side driver _unit) in _enemySides) then
        {
            _enemies set [count _enemies, _unit];
        };
    };
}
forEach _targets;

_enemies

BIS_fnc_enemyDetected:

/*
    Author: Jiri Wainar

    Description:
    Return true if unit knows about nearby enemy unit or driven vehicle.

    Parameter(s):
    _this: unit that is inspected

    Returns:
    _knowsAboutEnemy:bool

    Example:
    _knowsAboutEnemy:bool = _unit call BIS_fnc_enemyDetected;
    _knowsAboutEnemy:bool = [_unit(,_distance)] call BIS_fnc_enemyDetected;
*/

count (_this call BIS_fnc_enemyTargets) > 0

The first one fails to return hostile vehicles without a driver, even if other positions are occupied by enemy units, the second one fails because of that.

 

Using this as a temporary fix in my own missions, maybe someone comes up with a better solution:

_unit = player;
_enemySides = _unit call BIS_fnc_enemySides;
_enemies = (_unit neartargets 2000) apply {_x select 4} select {side _x in _enemySides AND {count crew _x > 0}};

This runs for 0.0976 ms on my rig, compared to  0.145243 ms of the BIS function.

 

Cheers

Share this post


Link to post
Share on other sites

If this thread is still a thing:

Possible improvement for BIS_fnc_numberDigits

[random 10000] call BIS_fnc_numberDigits; //0.0538 ms
toarray str random 10000 apply {parsenumber (tostring [_x])}; //0.01 ms

530% speed increase? Seems vast, or am I missing something?

 

Cheers

Share this post


Link to post
Share on other sites
4 hours ago, Grumpy Old Man said:

If this thread is still a thing:

Possible improvement for BIS_fnc_numberDigits


[random 10000] call BIS_fnc_numberDigits; //0.0538 ms
toarray str random 10000 apply {parsenumber (tostring [_x])}; //0.01 ms

530% speed increase? Seems vast, or am I missing something?

 

Cheers

 

Without random it's even 900% for me. Good find!

  • Like 1

Share this post


Link to post
Share on other sites
15 minutes ago, R3vo said:

 

Without random it's even 900% for me. Good find!

Currently optimizing some functions from my library (and for aircraft loadout dialog), getting rid of BI functions is a good idea most of the time, as you see. heh.

Also I'm getting addicted to increasing performance, especially with such promising results. Shedding off the milliseconds like mad.

 

Cheers

Share this post


Link to post
Share on other sites
5 hours ago, Grumpy Old Man said:

 


[random 10000] call BIS_fnc_numberDigits; //0.0538 ms
toarray str random 10000 apply {parsenumber (tostring [_x])}; //0.01 ms

 

Careful with fraction part. parseNumber parses decimal dot into zero, so for 12.34 you will get [1,2] for BIS_fnc_numberDigits and, surprise, [1,2,0,3,4] for parseNumber variant.

 

UPD. If it only used for integers, this can be even faster:

toarray str random 10000 apply {_x-48};

(decimal point converted to -2 in this variant)

 

UPD2. And negatives! parseNumber parses minus sign into zero too. {_x-48} makes -3 out of minus sign. Not very comfy, but at least distinguishable from real number digits.

Edited by pedeathtrian
  • Like 1

Share this post


Link to post
Share on other sites
18 hours ago, pedeathtrian said:

Careful with fraction part. parseNumber parses decimal dot into zero, so for 12.34 you will get [1,2] for BIS_fnc_numberDigits and, surprise, [1,2,0,3,4] for parseNumber variant.

 

UPD. If it only used for integers, this can be even faster:


toarray str random 10000 apply {_x-48};

(decimal point converted to -2 in this variant)

 

UPD2. And negatives! parseNumber parses minus sign into zero too. {_x-48} makes -3 out of minus sign. Not very comfy, but at least distinguishable from real number digits.

Removing the zeros from the array, nice. That's even faster, doing this with a set number it goes from 0.0079 ms using my attempt down to 0.0051 ms on my rig. Nice speed increase indeed!

If you know the culprits and handle the outcome of a negative number when needed it's definitely the way to go!

 

Cheers

Share this post


Link to post
Share on other sites
On 5/27/2017 at 5:41 AM, Grumpy Old Man said:

or am I missing something?


Yes

1234567 call BIS_fnc_numberDigits; //[1,2,3,4,5,6,7]
toarray str 1234567 apply {parsenumber (tostring [_x])}; //[1,0,2,3,4,5,7,0,0,0,0,6]

 

  • Like 1

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

×