Jump to content
thy_

[SOLVED] After transfer the unit to another group, in the new group, they not move

Recommended Posts

Guys, folks, dudes, 

 

What:

Here is where I make my day: I built a function where a specific group finds out a building, goes there and, after a while, they find a new building and go there too, over and over again. If a member of this group stays behind, this member is removed from the group. After being removed, that lone wolf will be allowed to find out their own buildings and go there too.

 

Issue:

The lone wolf unit, after being transferred to a new empty group (so they're the leader) the unit stands still, facing their newest waypoint over a building (so the step_one function ran), but is not allowed to move there, just sometimes shaking head and weapon but completely stuck. If I drop a enemy around, the lone wolf will engage, but never change their position. No clue what's happening here. No mods on. Only Arma 3. 

 

unit (soldier) stuck even with waypoints and speaking on radio.
Unit (soldier) stuck even with waypoints and speaking on the radio.

 

Context:

 DynamicSimulation is false in this case and I already tried to apply doMove, enableAI "PATH", but the lone wolf unit stays there, stuck.

 

 

Structure example I am using:

THY_fnc_step_one = {
    // This function makes a group find a building and, after that, move there.
    // Return nothing.
  
    params [...];
    private [...];
  
   // <DELETE OLD WAYPOINTS AND GIVE A NEW ONE STRAIGHT TO THE BUILDING>
   
    // If the group close enough to the building, execute "step_two".
    [...] spawn THY_fnc_step_two;
  
    // <CODE CODE CODE>
  
    // Return:
    true;
};

 

THY_fnc_step_two = {
    // This function makes a group, right after the arrival at the building, they wait a while before execute the "step_one" again.
    // Return nothing.
  
    params [...];
    private [...];
  
    // If some group's unit stay behind, remove the unit from the group:
    [...] spawn THY_fnc_remove_from_the_group;
    
    // If this original group arrive at the building as planned, take a break and execute again the "step_one":
    [...] spawn THY_fnc_step_one;
  
    // <CODE CODE CODE>
  
    // Return:
    true;
};

 

THY_fnc_remove_from_the_group = {
    // This function makes a single abandoned unit to be a lonewolf group leader allowed to find out their own buildings to visit.
    // Return nothing.
  
    params ["_faction", "_unit"];
	private [...];

	_newGrp = createGroup [_faction, true];
	[_unit] joinSilent _newGrp;
	[_faction, _unit] spawn THY_fnc_step_one;
	// Return:
	true;
};

 

 

 

Share this post


Link to post
Share on other sites
2 hours ago, thy_ said:

_newGrp = createGroup [_faction, true];

Dunno, can't see anything wrong with it. Have you checked your variables so they actually contain what you expect?

 

Also check the waypoints of the group after you added your new unit, maybe a "rogue" waypoint has snuck in...

Share this post


Link to post
Share on other sites

To work around the issue momentarily, I'm replacing that unit with a new one. It's an alternative with a much higher processing cost, but it's the way I found to not lose that unit left behind.

THY_fnc_remove_from_the_group = {
    // This function makes a single abandoned unit to be a lonewolf group leader allowed to find out their own buildings to visit.
    // Return nothing.
  
    params ["_faction", "_unit"];
    private [...];
	
    // Collecting the current unit features:
    _originalType = typeOf _unit;
    _originalPos = getPosATL _unit;
    _originalDir = getDir _unit;
    _originalDamage = damage _unit;
    // Deleting the current unit:
    deleteVehicle _unit;
    // Create the new group:
    _newGrp = createGroup [_faction, true];
    // Creating the new unit:
    _newUnit = _newGrp createUnit [_originalType, _originalPos, [], 0, "NONE"];
    // Bringing the original features:
    _newUnit setDir _originalDir;
    _newUnit setDamage _originalDamage;
    
    // Finally, making the lone wolf search and goes to their own building:
    [_faction, leader _newGrp] spawn THY_fnc_step_one;
    // Return:
    true;
};

 

Share this post


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

Dunno, can't see anything wrong with it. Have you checked your variables so they actually contain what you expect?

 

Currently, to check my variables I use systemChat str _variable; a lot. Can you recommend me a more efficient way to do this? 'Cause I'm checking a lot of things and I can't find what is causing the unit to stay in the same position, even when in combat.

Share this post


Link to post
Share on other sites
1 hour ago, thy_ said:

Can you recommend me a more efficient way to do this?

For output I use:

diag_log text format ["_varname = %1", _varname]; 

The format can obviously take multiple params if you wish to make them.

 

Then I open the log-file in an editor that updates without reload (I use vscode) and let the facts roll by, just remember to clear the log before running your tests. 🙂

 

 

 

Another few tips to make it more manageable:

1. Limit the test as much as possible while still reliably recreating the fault. An example could be to limit the number of units involved in the test.

2. If possible use a sterile environment. A separate mission is great but if that's too much work separate test subject from other mission logic by executing some things manually.

  • Thanks 1

Share this post


Link to post
Share on other sites

Show your step_one  script, an error interfering with the movement of the unit may be in it. 

Share this post


Link to post
Share on other sites
On 2/22/2023 at 1:18 PM, mrcurry said:

For output I use:

diag_log text format ["_varname = %1", _varname]; 

Then I open the log-file in an editor that updates without reload (I use vscode) and let the facts roll by, just remember to clear the log before running your tests. 🙂

 

I've read this page on the wiki about the diag_log but unfortunately I couldn't find out where that file is located.

 

gti6Jbx.png

 

 

EDITED: btw, I'm using now this function. Awesome for debug secondary feedbacks: https://community.bistudio.com/wiki/BIS_fnc_error 

Share this post


Link to post
Share on other sites
On 2/22/2023 at 12:19 PM, thy_ said:

// <DELETE OLD WAYPOINTS AND GIVE A NEW ONE STRAIGHT TO THE BUILDING>

What does this entail? Never ever delete the waypoint at index 0.

In fact, I'd say never delete the waypoints at all. Instead, give the group new waypoints and then set their current to the first new one you want them to follow.

Share this post


Link to post
Share on other sites
9 hours ago, Larrow said:

Never ever delete the waypoint at index 0.

Where can I read, what is the reason for this and what can it lead to?

Share this post


Link to post
Share on other sites

vKOBVy8.png

 

Morning for my timezone 😉

I've fixed the issue by adding a forEach looping in step_one, giving back the units group the basic features expected (because forward in other functions I need to deactivate some.  

    // Forcing unit basic setup to start the Occupy movement to prevent anomalies:
    {  // forEach of units _grp:
        _x enableAI "PATH";
        _x doFollow (leader _grp);  // crucial after use doStop. doMove works to "reactivate" the movement as well.
        _x setUnitCombatMode "YELLOW";
        sleep 0.25;
    } forEach (units _grp);

So my function "THY_fnc_remove_from_the_group" is back to simplicity:

Spoiler

THY_fnc_CSWR_OCCUPY_remove_unit_from_group = {
	// This function removes a specific unit left behind, and set them to a new group that is allowed to execute also the occupy-movement by itself.
	// Returns nothing.

	params ["_unit", "_ownerTag", "_wait"];
	private ["_txtDebugHeader", "_newGrp"];

	// Debug txts:
	_txtDebugHeader = "CSWR DEBUG >";
	// Debug message:
	if (CSWR_isOnDebugGlobal) then {
		systemChat format ["%1 '%2' > OCCUPY > A unit of '%3' has been removed as member to preserve the team movement.", _txtDebugHeader, _ownerTag, str (group _unit)];
		sleep 3;
	};
	// Create the new group:
	_newGrp = createGroup [side _unit, true];  // [side, deleteWhenEmpty]
	// Add the removed unit to the new group:
	[_unit] joinSilent _newGrp;
	// Cooldown to prevent crazy loopings:
	sleep _wait;
	// Restart the first OCCUPY step:
	[_newGrp, side _unit] spawn THY_fnc_CSWR_go_dest_OCCUPY;
	// Return:
	true;
};

 

 

That said, let me answer you, folks:

 

19 hours ago, Ibragim A said:

Show your step_one  script, an error interfering with the movement of the unit may be in it. 

 

Hey, @Ibragim A. Sure:

Spoiler

THY_fnc_CSWR_go_dest_OCCUPY = { 
	// This function sets the group to move and occupy buildings in a certain marker range. It's a looping.
	// Returns nothing.
	
	params ["_grp", "_faction"];
	private ["_txtDebugHeader", "_txtWarningHeader", "_ownerTag", "_destsList", "_spots", "_wp", "_leadStuckCounter", "_distLimiterFromBuilding", "_distLimiterFriendPlayer", "_distLimiterEnemy", "_wait", "_grpSize", "_regionToSearch", "_building"];
	
	// Error handling:
	if ( isNull _grp ) exitWith {};
	// Debug txts:
	_txtDebugHeader = "CSWR DEBUG >";
	_txtWarningHeader = "CSWR WARNING >";
	// Debug and warning purposes:
	_ownerTag = [_faction] call THY_fnc_CSWR_convertion_faction_to_owner_tag;
	// Initial values:
	_destsList = [];
	_spots = [];
	_wp = [];
	_leadStuckCounter = 0;
	private _getOutPos = [];
	// Declarations:
	_distLimiterFromBuilding = 10;  // Distance to activate occupy functions validations to team leader.
	_distLimiterFriendPlayer = 40;  // Distance to desactivate the AI teleport when player is around.
	_distLimiterEnemy = 200;  // Distance to desactivate the AI teleport when enemies (including player) are around.
	_wait = 10;  // Avoid crazy loopings in entery occupy functions. Be careful.
	_grpSize = count (units _grp);
	_grp setCombatMode "YELLOW";  // forcing to keep formation.
	// Forcing unit basic setup to start the Occupy movement to prevent anomalies:
		{  // forEach of units _grp:
			_x enableAI "PATH";
			_x doFollow (leader _grp);
			_x setUnitCombatMode "YELLOW";
			sleep 0.25;
		} forEach (units _grp);
	// Selecting the rith faction destination:
	switch ( _faction ) do {
		case BLUFOR: { _destsList = CSWR_destsOccupyBLU };
		case OPFOR: { _destsList = CSWR_destsOccupyOPF };
		case INDEPENDENT: { _destsList = CSWR_destsOccupyIND };
		case CIVILIAN: { _destsList = CSWR_destsOccupyCIV };
	};
	// Error handling:
	if ( _grpSize > 6 ) exitWith { ["%1 '%2' > OCCUPY > The current '%3' team size (%4) is too big for occupy movement integrity. Use teams composed from 1 to 6 members. For now, the group has been deleted.", _txtWarningHeader, _ownerTag, str _grp, _grpSize] call BIS_fnc_error; _grp deleteGroupWhenEmpty true; { deleteVehicle _x } forEach units _grp; deleteGroup _grp };
	// Check the available OCCUPY faction markers on map:
	_regionToSearch = getMarkerPos (selectRandom _destsList);
	// Selecting one building from probably many others found in that range:
	_building = [_grp, _regionToSearch, CSWR_occupyMarkerRange, _wait] call THY_fnc_CSWR_OCCUPY_find_building;  // return object.
	// If there's a building:
	if ( !isNull _building ) then {
		// Figure out if the selected building has enough spots for current team size:
		_spots = [_building, _grpSize] call BIS_fnc_buildingPositions;
		// If has enough spots for the whole current team size:
		if ( (count _spots) >= _grpSize ) then {
			// Delete old waypoints to prevent anomalies:
			for "_i" from count waypoints _grp -1 to 0 step -1 do { deleteWaypoint [_grp, _i] };  // waypoints get immediately re-indexed when one gets deleted, delete them from last to first.
			// Go to the specific building:
			_wp = _grp addWaypoint [getPosATL _building, 0];
			_wp setWaypointCombatMode "YELLOW";  // Open fire, but keep formation, trying to avoid those units stay far away from the team leader.
			_wp setWaypointSpeed "NORMAL";
			// Meanwhile the team leader is alive or their group to exist:
			while { (alive (leader _grp)) OR (!isNull _grp) } do {
				// if the leader is NOT awake:
				if ( (incapacitatedState (leader _grp)) == "UNCONSCIOUS" ) then {
					// Kill the AI leader to renew the team leadership:
					(leader _grp) setDamage 1;  // WIP <------------------------- NOT SURE IF IT WILL RUN PROPER WITH ACE.
					// Stop the while-looping:
					break;
				};
				// if team leader is close enough to the chosen building:
				if ( ((leader _grp) distance (getPosATL _building)) < _distLimiterFromBuilding ) then {
					// When there, execute the occupy function:
					[_building, _grp, _faction, _ownerTag, _wp, _distLimiterFromBuilding, _distLimiterEnemy, _distLimiterFriendPlayer, _wait] spawn THY_fnc_CSWR_OCCUPY_doGetIn;
					// Stop the while-looping:
					break;
				};
				// Check if the waypoint was deleted (sometimes bugs or misclick by zeus can delete the waypoint):
				if ( waypointType _wp == "" ) then {
					// Debug message:
					if ( CSWR_isOnDebugGlobal AND CSWR_isOnDebugOccupy ) then { systemChat format ["%1 '%2' > OCCUPY > '%3' team lost the waypoint for unknown reason. New search in %6 secs.", _txtDebugHeader, _ownerTag, str _grp, count units _grp, count _spots, _wait]; sleep 1 };
					// Small cooldown to prevent crazy loopings:
					sleep 3;
					// Restart the first OCCUPY step:
					[_grp, _faction] spawn THY_fnc_CSWR_go_dest_OCCUPY;
					// Stop the while-looping:
					break;
				};
				// Check if the leader is not stuck in their way to the building and, if they are, give a timeout to restart the whole function again:
				if ( (unitReady (leader _grp)) AND ((lifeState (leader _grp)) != "INJURED") AND ((incapacitatedState (leader _grp)) != "SHOOTING") ) then {
					_leadStuckCounter = _leadStuckCounter + 1;
					// Debug message:
					if ( CSWR_isOnDebugGlobal AND CSWR_isOnDebugOccupy ) then { systemChat format ["%1 '%2' > OCCUPY > '%3' leader looks stuck %4 time(s).", _txtDebugHeader, _ownerTag, str _grp, _leadStuckCounter]; };
					if ( _leadStuckCounter == 5 ) then {
						// Find position minimum 10m (_distLimiterFromBuilding) from (leader _grp) but not further than 20m, not closer than 4m to any other object, not in the water, maximum gradient of 0.7, not on the shoreline:
						_getOutPos = [(leader _grp), _distLimiterFromBuilding, (_distLimiterFromBuilding * 2), 4, 0, 0.7, 0] call BIS_fnc_findSafePos;
						// Teleport to the safe position out:
						(leader _grp) setPosATL [_getOutPos select 0, _getOutPos select 1, 0];
						// Destroying the position just in case:
						_getOutPos = nil;
						// Restart the first OCCUPY step:
						[_grp, _faction] spawn THY_fnc_CSWR_go_dest_OCCUPY;
						// Stop the while-looping:
						break;
					};
				};
				// If leader not close enough to the building, let's CPU breath to the next distance checking:
				sleep _wait;
			};  // While-loop ends.
		// If has NO spots for the whole team:
		} else {
			// Debug message:
			if ( CSWR_isOnDebugGlobal AND CSWR_isOnDebugOccupy ) then { systemChat format ["%1 '%2' > OCCUPY > The building '%3' has %4 spot(s) but '%5' has %6 men.", _txtDebugHeader, _ownerTag, typeOf _building, count _spots, str _grp, count (units _grp)] };
			// Cooldown to prevent crazy loopings:
			sleep _wait;
			// Restart the first OCCUPY step:
			[_grp, _faction] spawn THY_fnc_CSWR_go_dest_OCCUPY;
		};
	// If a building is NOT found:
	} else {
		// Warning message:
		["%1 OCCUPY > An OCCUPY marker looks not close enough or without good range set ('CSWR_occupyMarkerRange') to allowed buildings for OCCUPY movement. New search in %2 secs.", _txtWarningHeader, _wait] call BIS_fnc_error;
		// Cooldown to prevent crazy loopings:
		sleep _wait;
		// Restart the first OCCUPY step:
		[_grp, _faction] spawn THY_fnc_CSWR_go_dest_OCCUPY;
	};
	// Return:
	true;
};

 

 

 

 

10 hours ago, Larrow said:

What does this entail? Never ever delete the waypoint at index 0.

In fact, I'd say never delete the waypoints at all. Instead, give the group new waypoints and then set their current to the first new one you want them to follow.

 

Hey, @Larrow, here's what I'm doing:

 

// Delete old waypoints to prevent anomalies:
for "_i" from count waypoints _grp -1 to 0 step -1 do { deleteWaypoint [_grp, _i] };  // waypoints get immediately re-indexed when one gets deleted, delete them from last to first.
// Go to the specific building:
_wp = _grp addWaypoint [getPosATL _building, 0];

 

 

1 hour ago, Ibragim A said:

Where can I read, what is the reason for this and what can it lead to?

 

All I need is to add a waypoint to the group for the first move ("step_one"). The group will go to the waypoint which will always be attached to a building. When the group arrives at the building, the group gets into the building and stays there for a long time. When the group needs to leave the building, the group simply calls again "step_one" which will search for a building and attach a new waypoint to it. "But why delete the waypoint when the unit arrived at the building though?" Because many times in tests, especially in buildings with more than one floor or with complex interiors, the group could not touch the waypoint and, for some reason, on rare occasions, they wouldn't move to the next building because they were still trying to touch the waypoint of the building where they are, stand still.

To resolve the issue without deleting the waypoint from the current group's building, I tried using setWaypointCompletionRadius but "the completion radius is currently important for units moving in the Combat mode" and I can't expect the group will be in Combat mode always during the occupy-movement. 

 

Share this post


Link to post
Share on other sites
22 hours ago, Ibragim A said:

Where can I read, what is the reason for this and what can it lead to?

The waypoint at index 0 is not an added waypoint per se. Just the act of placing a group in the editor/spawning automatically gives the group an index 0 waypoint relative to the position they were placed/spawned. Adding a single waypoint to a group would in fact add index 1.

I have seen deleting every waypoint including index 0 cause oddities before, I am not sure I've ever read anything official just based on my own experiences.

  • Thanks 1

Share this post


Link to post
Share on other sites
20 hours ago, thy_ said:

All I need is to add a waypoint to the group for the first move ("step_one").

As mentioned above index 0 is not the first move, it is their initial starting point.

 

20 hours ago, thy_ said:

"But why delete the waypoint when the unit arrived at the building though?" Because many times in tests, especially in buildings with more than one floor or with complex interiors, the group could not touch the waypoint and, for some reason, on rare occasions, they wouldn't move to the next building because they were still trying to touch the waypoint of the building where they are

If you set the group's current waypoint to the waypoint just added then they will ignore trying to reach their current, as it is no longer their current, you have just overridden this by changing their current.

params[ "_grp" ];

//Give group an unreachable waypoint
_wp1 = _grp addWaypoint[ /*some unreachable pos*/, 0 ];
//Give group a secondary waypoint
_wp2 = _grp addWaypoint[ /*some other pos*/, 0 ];

//Group will ignore _wp1 and move straight to _wp2
_grp setCurrentWaypoint _wp2;

 

20 hours ago, thy_ said:

To resolve the issue without deleting the waypoint from the current group's building, I tried using setWaypointCompletionRadius but "the completion radius is currently important for units moving in the Combat mode" and I can't expect the group will be in Combat mode always during the occupy-movement.

Again, use setCurrentWaypoint. No need to try and make the group reach their current one by changing the completion radius, just skip it completely by giving them a new current.

  • Like 1

Share this post


Link to post
Share on other sites

I've also come across something similar.
But the setCurrentWaypoint command also has its drawbacks. So, for example, if waypoints have a statement, this code will be called if you use this command to change the current point to another one.

_wp1 = g1 addWaypoint[ [2000,2000,0], 0];
_wp1 setWaypointType "MOVE";
_wp1 setWaypointStatements ["true","systemchat 'goal'"];

_wp2 = g1 addWaypoint [[1000,1000,0], 0];
_wp2 setWaypointType "MOVE";
g1 setCurrentWaypoint _wp2;

The chat will say "goal", despite the fact that the first point will not be reached.

  • Like 1

Share this post


Link to post
Share on other sites
On 2/26/2023 at 10:37 AM, Ibragim A said:

The chat will say "goal", despite the fact that the first point will not be reached.

Maybe this is something that should be brought up on the feedback tracker, as the waypoint is never completed so the statement condition should really never even be checked, let alone the statement executed.

What happens if you skip several waypoints that have statements like this? Are they all executed, or only the current?

Sounds like a logic error to me in the waypoint code.

 

I suppose a quick user fix would be before using setCurrentWaypoint to check if the current waypoints statement condition is false or the statement is blank and if not then set it so.

Share this post


Link to post
Share on other sites
10 hours ago, Larrow said:

The waypoint at index 0 is not an added waypoint per se. Just the act of placing a group in the editor/spawning automatically gives the group an index 0 waypoint relative to the position they were placed/spawned. Adding a single waypoint to a group would in fact add index 1.

I have seen deleting every waypoint including index 0 cause oddities before, I am not sure I've ever read anything official just based on my own experiences.

 

So I've fixed that like this down below. What do you think? In my tests, everything looks fine. if I got oddities, I will change exactly what you already said above. 

// Delete old waypoints to prevent anomalies:
for "_i" from count waypoints _grp -1 to 1 step -1 do { deleteWaypoint [_grp, _i] };  // waypoints get immediately re-indexed when one gets deleted, delete them from last to first.
// Go to the specific building:
_wp = _grp addWaypoint [_bldgPos, 1];

That's right, I've tried earlier with a solution with setWaypointStatements, but I got the same bad result. 

 

7 hours ago, Ibragim A said:

if waypoints have a statement, this code will be called if you use this command to change the current point to another one. (...) The chat will say "goal", despite the fact that the first point will not be reached.

 

Share this post


Link to post
Share on other sites

Definitely, @Larrow my solution brings (during the stress-testing) oddities where some groups stopped to include new waypoints for no apparent reason. That said, I've remove all "deleteWaypoint _wp" from the code and rebuilt that block as you said. Now, the troops are creating waypoints for 30min with no inconsistencies.

 

// Go to the specific building:
_wp = _grp addWaypoint [_bldgPos, 0];
_grp setCurrentWaypoint _wp;



😉

 

QsyN1Fl.png

  • Like 1

Share this post


Link to post
Share on other sites
14 hours ago, Larrow said:

What happens if you skip several waypoints that have statements like this? Are they all executed, or only the current?

Sounds like a logic error to me in the waypoint code.

The statement is called for each waypoint that the script jumps over. I have encountered this and because of this problem I was forced to not use setCurrentWaypoint and use waypoint deletion instead.
I agree that this is at least not logical.

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

×