Jump to content
Sign in to follow this  
stilton

End of script termination?

Recommended Posts

Ok i'm not sure if this is a silly question..

..But here goes.

You can use exitWith{} to exit the scope of loops, which i understand...

You can use terminate to forcibly terminate a 'child script' before it completes, using its' handle as an argument...

But am i correct in thinking though that when a script successfully runs to its end, its done, and the _handle would return true at this point... and it'll have minimal impact on performance simply having the _handle variable floating about in memory...

Still, if the _handle returns true... that means it's still sort of 'held in memory' somewhere... So i'm a little concerned after the 500th bad guy has been eliminated i have all these 'handles' floating about in the ether.

i was simply going to put if (true) exitWith{}; at the end of my script but the biki sort-of warns against doing that non-specifically.

Share this post


Link to post
Share on other sites

Do you see the memory rising when spawning threads with handles?

Test with something like that:

0 = [] spawn {
while {true} do {
	_handle = [] spawn {
		_res = 1;
		_res = _res + 1;
	};
	sleep 0.01;
};
};

Share this post


Link to post
Share on other sites
Do you see the memory rising when spawning threads with handles?

No 'stats' collected about memory consumed or anything, truthfully it was more of a (terrible) guesstimation :) that came with having spawned 100 or so AI with the attached script and then having the game feel more 'sluggish'

... Which is probably more to do with the 100 AI being ordered around in another script than the one simple script im fussing over now. :)

@kk: that's another misunderstanding i've made lol, oops.. :) [ guess i didnt read the waitUntil scriptDone biki page carefully enough and took some stuff for granted there, ive hardly use 1% of all BI's functions :) ]

Still, since i'm still wondering... Maybe i wasn't clear enough?

Once a script attached to a unit, in it's init has run through to 'completion', and the unit is killed.. and the unit is deleted (deleteVehicle) do i need to do anything to 'clean' the script up?

I don't think so, as i understand it, once the script has finished running through, it's done and i dont need to worry about it; but im asking for the sake of my own sanity/knowledge :)

To ask a further possibly crazy question... and this has no actual benefit to me, other than 'knowledge'

If i have a script started from an unit's initialization line... and the unit is deleted, by that very script itself... Well this is where i start to go a bit cross-eyed, obviously the script isn't a 'child' of that object in terms of the game engine.. because otherwise deleting the unit / its own parent would delete the script (scriptception?)

So i'm left wondering is that what the 'handle' is actually for, and again, do i need to worry about deleting the 'handles' independantly of the units?

Or am i worrying about nothing and is that what you were trying to illustrate by asking me to see how many weeks it would take to crash my pc by spawning infinite handles? :)

Edited by Stilton

Share this post


Link to post
Share on other sites
Once a script attached to a unit, in it's init has run through to 'completion', and the unit is killed.. and the unit is deleted (deleteVehicle) do i need to do anything to 'clean' the script up?

I don't think so, as i understand it, once the script has finished running through, it's done and i dont need to worry about it; but im asking for the sake of my own sanity/knowledge :)

To ask a further possibly crazy question... and this has no actual benefit to me, other than 'knowledge'

If i have a script started from an unit's initialization line... and the unit is deleted, by that very script itself... Well this is where i start to go a bit cross-eyed, obviously the script isn't a 'child' of that object in terms of the game engine.. because otherwise deleting the unit / its own parent would delete the script (scriptception?)

Yes and no, you can spawn off all sorts of crazy things from an init line that may or may not terminate on a unit's death/deletion. It really depends what you are spawning off and how it is coded. The question is too broad to give a definitive answer I would say, so maybe post up what you are actually doing so we can have a look.

So i'm left wondering is that what the 'handle' is actually for, and again, do i need to worry about deleting the 'handles' independantly of the units?

If you are execVM/spawning the script, then the handle is a reference to the script. See here:

https://community.bistudio.com/wiki/Script_(Handle)

You can see if it's running or terminate it basically. If you are calling some code, then the handle could be a return value (ie: what the function calculates depending on how it is written).

Or am i worrying about nothing and is that what you were trying to illustrate by asking me to see how many weeks it would take to crash my pc by spawning infinite handles? :)

Pretty much. I wouldn't really get bogged down in the <0.5Mb or whatever memory Arma allocates to manage script handles. As you say, spawning in 100 units and ordering them about will be your chief culprit of shitty performance.

Share this post


Link to post
Share on other sites

Ok thanks for the information, i appreciate i'm drifting into asking kind of 'theory' questions opposed to actual specific examples here...

Mainly because whilst i've been scripting using the init boxes since.. a while (ofp / years probably lol),

it's only the last few days/week i've gone ahead and installed the dedi server and really tried to script some pretty complicated stuff (for me personally, at least) and started tackling things like locality issues, last time i got this far into making a mission, i switched from the editor to dedi.. everything was fine, then when i got a few people in to help me test it, it all went to shit because of the locality issues... :D

I'm reluctant to put up the code because it's probably quite amateur-hour looking to some of the more experienced scripters ... but in short i was trying my hand at remaking a sort of tailored version of the insurgency/coop mission from arma, so i had this script running on pretty much every enemy spawned...

_unit = _this select 0;
_isGuard = _this select 1;

_debug = cacheDebug;
_leader = leader _unit;
_thisGrp = group _unit;
//_unitName = str _unit;
_unitName = name _unit;
_grpDebugMarker = [];


sleep 2;
if (_debug) then {
//setPlayable _unit;
//addSwitchableUnit _unit;
//_knownTargetCount = _unit 
//_unitName = str _unit;

_grpDebugMarker = createMarker [_unitName, (position _unit)];
_grpDebugMarker setMarkerShape "ICON";
_grpDebugMarker setMarkerType "mil_dot";
_grpDebugMarker setMarkerColor "ColorPink";
//_grpDebugMarker setMarkerText _unitName;

if ((_leader) == (leader _thisGrp)) then { _grpDebugMarker setMarkerType "hd_warning"; _grpDebugMarker setMarkerText _unitName; }else{  _grpDebugMarker setMarkerType "hd_dot"; _grpDebugMarker setMarkerText "";};
};

//  This is a spawned enemy.  westPlayers is a global array with all playable West group in it.
if (isServer) then {
//_FriendlyTargets = {side _x == west} count allUnits; 
while {alive _unit} do {   // whilst this dude is alive     
	_ready = unitReady _unit;

	_grpSize = count units _thisGrp;

	_leader = leader _unit ;
	_thisGrp = group _unit; 
	_thisPos = position _unit;
	_searchRad = 2500;	
	_distToFriendly = 3000;
	_joiningDistance = 225;

	_randomTarget = [];
	_randomTarget = westPlayers call BIS_fnc_selectRandom;

	if ((_leader) == (leader _thisGrp)) then {

		_thisGrp setCombatMode "RED"; 
		if (!_isGuard) then { _unit setBehaviour "AWARE"; _unit setSpeedMode "FULL"; };

		if (count units _thisGrp < 4) 
			then {

				_nearestunits = nearestObjects [_thisPos,["Man"],_searchRad];   // find nearest friendlies
				_nearestfriendlies = [];  // put into this array below

				if (east countSide _nearestunits > 0) then{
				{
				_nearUnit = _x;
				if(side _nearUnit == east && ((group _nearUnit) != _thisGrp)) then {_nearestfriendlies = _nearestfriendlies + [_nearUnit]};
				} forEach _nearestunits;
				};

				if (count _nearestfriendlies > 0) then {
				_closestfriendly = (_nearestfriendlies select 0);
				_distToFriendly = (position _closestfriendly) distance _thisPos;

				if (_distToFriendly < _joiningDistance) then { _oldGroup = (group _unit);   { [_x] joinSilent (group _closestfriendly) } forEach units _oldGroup;  _leader = leader _unit; _thisGrp = group _unit;     };

				};




			};

		sleep 5;

		if (_ready) then { 
			_wp0 = _thisGrp addWaypoint [ position _randomTarget, 200 ]; 
			if (_isGuard) then { _wp0 setWaypointSpeed "LIMITED"; }else{ _wp0 setWaypointSpeed "FULL"; };
			if (_isGuard) then { _wp0 setWaypointFormation "COLUMN"; }else{ _wp0 setWaypointFormation "LINE"; };
			//_wp0 setWaypointCombatMode "RED";  
			};

		};
		// Incase the leader joined this person, they might not be the leader anymore, or in the same group, etc.
		_leader = leader _unit;
		_thisGrp = group _unit;
		// _unit globalChat "Off to get some guys";

	if (_debug) then { 
		_grpDebugMarker setMarkerPos _thisPos; 
		if ((_leader == leader _thisGrp)) 	then { _grpDebugMarker setMarkerType "hd_warning"; _grpDebugMarker setMarkerText _unitName; 
											}else{  _grpDebugMarker setMarkerType "hd_dot"; _grpDebugMarker setMarkerText "";};
		};


	// Update debug marker after all is said and done
	[b]if ((_leader) == (leader _thisGrp)) then { _grpDebugMarker setMarkerType "hd_warning"; _grpDebugMarker setMarkerText _unitName; }else{  _grpDebugMarker setMarkerType "hd_dot"; _grpDebugMarker setMarkerText "";};		[/b]
	sleep 5;


};	
};
// This should be applied on all clients
waitUntil{!alive _unit};
if (_debug) then { _grpDebugMarker setMarkerType "loc_Cross"; };

checked = false;
//hint "He died!";
_checkForIntelAction = _unit addAction ["Check for Intel", "checkForIntel.sqf",[westPlayers],8,true,true,"","true" ];

// allow time to check for intel then delete
sleep 240;
if (_debug) then { deleteMarker _grpDebugMarker };
deleteVehicle _unit;
//if (true) exitWith{};

One thing i'm a bit miffed about is The debug markers apply to the all enemies as 'squad leaders' with the 'warning' marker as opposed to the 'dots' -- it must be a logic error on my side, but i cant work out where ive gone wrong there... since i assumed the check you can see ive put in multiple places, if group leader == leader should, as far as i was reading it.. mean its only true if the unit is the group leader... But they all have the 'squad leader' marker.

I know that code is a clusterfuck so i've bolded the bit i'm talking about, not sure if it will work inside code tags, so just incase...

if ((_leader) == (leader _thisGrp)) then { _grpDebugMarker setMarkerType "hd_warning"; _grpDebugMarker setMarkerText _unitName; }else{  _grpDebugMarker setMarkerType "hd_dot"; _grpDebugMarker setMarkerText "";};

What i can't work out is why this isn't really taking effect... The part where it changes the marker to a cross when they die works perfectly, but i'm missing something... :D

Thanks for your information/help thus far anyway!

Edited by Stilton

Share this post


Link to post
Share on other sites

You could probably do with a redesign for your script to help cut back on the script scheduler overhead.

As you mention, you run this script on each unit and it lurks in the background, waiting until they die, then eventually deletes them. So if you imagine you've got 100 guys in the mission, then you've got an equal number of spawned scripts (also if you use other mods/mission scripts then you may have more).

I would do the following:

1 - Create your markers locally. Maybe change the marker name from _unitName to _unit.

2 - I haven't tested it, but you most likely want to do if (_unit == leader _thisGrp) then { blah blah.... to get markers changed for a leader.

3 - Run your targetting and group merge scripts to encompass all the groups. That way you don't run them on every unit, just one script that checks everything. Like this:

// 0 = [] execVM "scriptname.sqf";

if (isServer) then {
waitUntil {
	time > 1
};
while {true} do {
	// find enemy groups (assume east)
	{
		_grp = _x;
		if not (isNull _grp) then {
			if (side _grp == east) then {
				if (count units _grp > 0) then {
					_alive = {alive _x} count units _grp;
					if (_alive > 0) then {
						_leader = leader _grp;
						if (_alive < 4) then {
							_nearestFriends = _leader nearEntities ["SoldierEB",225];
							{
								if (group _x != _grp) exitWith {
									(units _grp) joinSilent (group _x)
								};
							} forEach _nearestFriends;
						} else {
							if (unitReady _leader) then {
								_randomTarget = westPlayers call BIS_fnc_selectRandom;
								_wp = _grp addWaypoint [position _randomTarget,200];
								_wp setWaypointBehaviour "AWARE";
								_wp setWaypointCombatMode "RED";
								if (_grp getVariable ["isGuard",false]) then {
									_wp setWaypointSpeed "LIMITED";
									_wp setWaypointFormation "COLUMN";
								} else {
									_wp setWaypointSpeed "FULL";
									_wp setWaypointFormation "LINE";
								};
							};
						};
					};
				} else {
					deleteGroup _grp
				};
			};
		};
	} forEach allGroups;
	sleep 5;
};
};

Untested of course, but put the script exec line in the initline of a logic or other object on the map. The idea is it loops through all the groups, and if they are east, then merges them to a bigger group if in range and they are small, or sets them a WP to hunt the players if the group is big enough already.

You'll also need to put a line in the init of all the enemy group leaders:

Either:

group this setVariable ["isGuard",true];
// or
group this setVariable ["isGuard",false];

4 - Move the death stuff over to a "killed" eventhandler. Add it in the initline for each unit and it will fire on clients and server.

https://community.bistudio.com/wiki/Arma_3:_Event_Handlers#Killed

Sorry I've ran out of time to type more out but you get the idea. Hope that helps. :)

Share this post


Link to post
Share on other sites

ah cheers for your help mate, although you really shouldn't have gone to any trouble :D

part of me is too lazy to go about 'redesigning' simply because it works now.. its not flawless but it works.. and part of me is scared to start 'redesigning' and breaking it all to shit :D

Although, clearly i see what you're saying about putting the group-consolidation into a single script that checks all groups...

The reasoning i have a this script running on every unit is because originally it was just a small script that added an addaction to the corpse, allowing you to : 'checkForIntel.sqf' which adds markers to the map depicting where 'possible cache locations' are... depending on, if he is carrying intel (just a random number check) and then it does another random to see the 'strength' of the intel... and then the script is done...

But as you can see, slowly but surely ive 'tacked on' this group consolidation idea and yeah, its grown into the monster it is...

...Silly way to implement it, thanks for the suggestion/advice its a much better idea to do it once on a 'global' script checking all east groups! :D

Actually... re-reading, thanks for the advice and the 99% of a script that actually does it too ;)

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  

×