Jump to content
RCA3

Best way to use calculatePath and addEventHandler PathCalculated?

Recommended Posts

What's the best way to use calculatePath and addEventHandler PathCalculated, to pass positions to a group to form waypoints?

Cheers.

Share this post


Link to post
Share on other sites

The example on the biki works well for me. I adapted the one that places markers to make an array of road pieces that I then pass to setdriveonpath

Share this post


Link to post
Share on other sites

Moving a vehicle from A to B, I don't really understand the difference between a simple addWaypoint  to B and a setDriveOnPath on path calculated points A, A1, A2,...B.

I can see the calculatePath command can run for an alternate vehicle. Well. As you can choose the behavior in both cases, is that the only "advantage" using this heavier code?

Share this post


Link to post
Share on other sites
On 11/19/2019 at 12:39 PM, Tankbuster said:

The example on the biki works well for me. I adapted the one that places markers to make an array of road pieces that I then pass to setdriveonpath

Quote

myroads = [];

(calculatePath ["wheeled_APC","safe",(getMarkerPos "mrka"),(getMarkerPos "mrkb")]) addEventHandler ["PathCalculated",{
    {
        _mrk = createMarker ["marker" + str _forEachIndex, _x];
        _mrk setMarkerType "mil_dot";
        _mrk setMarkerText str _forEachIndex;

        myroads pushBack _x;
    } forEach (_this#1);
}];

hint str myroads;

We know this runs twice, and that is probably why I get an empty array as result.

Can you enlighten us on how you grabbed those points?

Thanks.

 

@pierremgi

People complain a lot of vehicles not driving on roads, especially with long journeys, this makes sure it uses them.

Share this post


Link to post
Share on other sites
10 minutes ago, RCA3 said:

@pierremgi

People complain a lot of vehicles not driving on roads, especially with long journeys, this makes sure it uses them.

 

Well. Imho, the addWaypoint process and the calculated path is same, for the same vehicle and the same behavior. If I'm right, the addWaypoint (when running in game) starts with a path calculation (the longer journey, the greater delay before move). So probably with the same algorithm.

 

How things could work differently? It's my true question. I'm always in search for performance, trying to avoid heavier script than necessary.

Share this post


Link to post
Share on other sites
57 minutes ago, pierremgi said:

How things could work differently? It's my true question. I'm always in search for performance, trying to avoid heavier script than necessary.

Well, in my case right now (i actually like the waypoint pathfinding too 🙂) I'm picking up roads in radius and trying to go from A to B through connected roads, which if I just add a waypoint on B it won't happen (on foot).

Share this post


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

We know this runs twice, and that is why I get an empty array as result.

Can you enlighten us on how you grabbed those points?

Thanks.

 

You need to be a bit clearer. It runs twice? Who is 'we'? Exactly what runs twice?

 

I've never seen it run twice. Your code does return an empty array, but the markers are created.

Share this post


Link to post
Share on other sites

 

I've added a few lines to your code.

 

myroads = [];

(calculatePath ["wheeled_APC","safe",getpos player,getpos pathend]) addEventHandler ["PathCalculated",{
    {
        _mrk = createMarker ["marker" + str _forEachIndex, _x];
        _mrk setMarkerType "mil_dot";
        _mrk setMarkerText str _forEachIndex;
	diag_log format ["%1", _x];
        myroads pushBack _x;
    } forEach (_this#1);
}];
diag_log format ["%1, %2", count myroads, myroads];
hint str myroads; 

I'm guessing myroads is empty because you haven't waited for the calculatepath command to finish. My code does output positions to the rpt.

 

A couple of things to note.

 

The positions you get back are ASL, so be aware if you're giving waypoints based on them.

This isn't foolproof, if the start and end are close together, some of the returned points will be offroad.

 

This command and it's eventhandler are, I think, intended to get the PREDICTED path a given vehicle will take between 2 points. I'm not sure, perhaps because I've misunderstood you, that this command is the best way to achieve what you are trying to do

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
3 hours ago, pierremgi said:

Moving a vehicle from A to B, I don't really understand the difference between a simple addWaypoint  to B and a setDriveOnPath on path calculated points A, A1, A2,...B.

I can see the calculatePath command can run for an alternate vehicle. Well. As you can choose the behavior in both cases, is that the only "advantage" using this heavier code?

Because this command is much quicker than actually sending a vehicle from a to b. It allows the mission maker to predict the route the vehicle will.

I use it to find a nice flat, open and straight section of road on which to spawn a roadblock for players to operate and it works well.

  • Thanks 1

Share this post


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

You need to be a bit clearer. It runs twice? Who is 'we'? Exactly what runs twice?

I'm sorry, I assumed everybody read the same I did. Here:

https://forums.bohemia.net/forums/topic/151099-scripting-discussion-dev-branch/?do=findComment&comment=3362335

 

1 hour ago, Tankbuster said:

I'm guessing myroads is empty because you haven't waited for the calculatepath command to finish. My code does output positions to the rpt.

I'll try that out. Thanks.

 

1 hour ago, Tankbuster said:

the PREDICTED path a given vehicle will take between 2 points

Hum, i see. It's not intended to be passed to a group. Ok... So you're saying it can't be used in realtime? Just extractable from RPT?

 

1 hour ago, Tankbuster said:

diag_log format ["%1", _x];

diag_log format ["%1, %2", count myroads, myroads];

Thanks.

Edited by RCA3

Share this post


Link to post
Share on other sites

You can pass it to a group. You had it mostly right, pushback each position to an array and do with it what you will. Just be sure to give the array time to be fully populated. The way you coded it, the eventhandler hadn't finished (or even started) before you hinted the myroads variable. calculatepath can be quite slow; asking it to do a SAFE wheeled_APC all the way across Altis takes a couple of seconds, you see.

 

Not really sure what Nomisum is finding on that linked thread. I've never seen it execute twice, though I've never used the output in the same way he did. As I said earlier, I use an adapted version of the snippet that makes markers, BUT, I get the road object at the position given using roadAt and then pushbackUnique them into an array for later use, so any duplicates would be eradicated. I use roadAt because I'm specifically interested in positioning a roadblock as I mentioned to Pierre just now.

  • Thanks 1

Share this post


Link to post
Share on other sites

As for the EH running twice here's what I got:

Quote

myroads = [];

 

private _obj = (calculatePath ["wheeled_APC","safe",(getMarkerPos "mkra"),(getMarkerPos "mkrb")]) addEventHandler ["PathCalculated",{
    diag_log format ["1: %1", _this];
    {
        _mrk = createMarker ["marker" + str _forEachIndex, _x];
        _mrk setMarkerType "mil_dot";
        _mrk setMarkerText str _forEachIndex;

 

         diag_log format ["2: %1", _x];

         myroads pushBack _x;
    } forEach (_this#1);
}];

RPT:

Quote

23:42:09 "1: [Agent 0x7c284100,[[2832.5,5926.5,4.76318],[2835.5,5929.5,4.76818],[2836.5,5930.5,4.77443],[2837.5,5931.5,4.78693],[2837.79,5931.73,4.79158],[2843.41,5941.37,4.893],[2849.99,5952.96,5.02229],[2857.99,5965.46,5.25485],[2865.19,5977.21,5.37144],[2865.5,5977.5,5.38068],[2865.59,5977.85,5.38588],[2870.13,5987.01,5.4393],[2870.61,5994.33,5.58428],[2869.44,6002.35,5.69913],[2867.53,6010.81,5.82365],[2866.45,6017.6,5.94606],[2867.43,6022.67,6.21086],[2869.25,6026.22,6.47965],[2876.78,6037.43,4.08557],[2885.06,6050.14,6.41802],[2887.41,6053.97,6.27706],[2889.84,6057.75,5.97758],[2893.69,6063.65,5.92324],[2903.99,6079.42,6.88435],[2915.87,6097.34,9.13051],[2924.47,6105.95,9.95093],[2932.89,6108.16,10.3154],[2943.15,6103.45,10.2614],[2953.13,6095.56,10.0003],[2962.18,6089.5,9.80969],[2975.74,6082.99,9.60952],[2992.74,6076.11,10.3796],[3008.17,6073,11.5054],[3019.69,6074.79,12.8642],[3026.56,6080.63,13.4572],[3028.9,6088.85,14.0242],[3028.39,6097.77,14.1007],[3025.07,6106.63,14.1813],[3019.24,6114.63,15.406],[3012.  (< - - It actually ends like this)
23:42:09 "2: [2832.5,5926.5,4.76318]"
"[...All Positions in between...]"
23:42:09 "2: [2970.86,6207.86,30.856]"
23:42:09 "1: [Agent 0x7c284100,[[2970.5,6207.5,30.8569],[2970.5,6207.5,30.8569]]]"
23:42:09 "2: [2970.5,6207.5,30.8569]"
23:42:09 "2: [2970.5,6207.5,30.8569]"

 

Same result with: isNil { calculatePath ...}

 

As for my question, I guess it's a bit different now:
Any reliable way to get the result of calculatePath and EH PathCalculate without being a guess estimate sleep time?

I mean i can pushBack each position to a global array/variable inside the EH, but i need to pass the result to a private group variable, thus waiting would be the more obvious option for me since i can't pass the group inside the EH. Does it make sense? I would be running this on multiple groups, each having their own path.

Share this post


Link to post
Share on other sites

@pierremgi the cmd is useful for visualization of low level pathfinding, and to debug issues, to find what is best waypoint placement and so on

 

so this lowl level insights gives a lot of option to make use of in creative ways

Share this post


Link to post
Share on other sites

Thanks Killzone Kid.

What do you guys think about this?

 

Quote

private _obj = calculatePath ["wheeled_APC","safe",[2832.9,5927.79,0],[3107.46,6036.61,0]];

_obj addEventHandler["PathCalculated", {
    params ["_agent", "_path"];
    private _patharray = [];

    {
        _mrk = createMarker ["marker" + str _forEachIndex, _x];
        _mrk setMarkerType "mil_dot";
        _mrk setMarkerText str _forEachIndex;

        _patharray pushBack _x;

    }forEach _path;

    diag_log format ["1: %1", count _path];

    if (_agent getVariable ["calcpath", []] isEqualTo []) then{
        _agent setVariable ["calcpath", _patharray];
    };
}];

waitUntil {!(_obj getVariable ["calcpath", []] isEqualTo [])};

private _path = _obj getVariable ["calcpath", []];

hint str [(alive _obj), _obj getVariable ["calcpath", []]];

diag_log format ["2: %1", count (_obj getVariable ["calcpath", []])];

 

Is it possible _obj gets deleted right after waitUntil before i register _path = _obj getVariable ["calcpath", []]; ?

Share this post


Link to post
Share on other sites

Code from previous post seems to be working well.

Apparently only one calculatePath (or Pathcalcuted) can be run at a time. Solved that by creating a global agent and sleeping until agent is null previous to calling code.

Edited by RCA3

Share this post


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

Code from previous post seems to be working well.

Apparently only one calculatePath (or Pathcalcuted) can be run at a time. Solved that by creating a global agent and sleeping until agent is null previous to calling code.

Good spot. Can add that info to the biki page?

Share this post


Link to post
Share on other sites
13 hours ago, RCA3 said:

Apparently only one calculatePath (or Pathcalcuted) can be run at a time.

Not sure I understand 

Share this post


Link to post
Share on other sites
21 hours ago, RCA3 said:

Apparently only one calculatePath (or Pathcalcuted) can be run at a time.

Ok, this is wrong.

What i'm getting is apparently related to addWaypoint somehow.

If I doMove units to the calculated path, they all go, if I give them waypoints, only some go.

Demo

 

Edit: if using addWaypoint ([] spawn { hint str diag_activeSQFScripts; }) reveals script still running, doMove exits sqf.

Share this post


Link to post
Share on other sites

Here's one method "apparently" working with 50 groups (100 AI) from Agia Marina's beach to Kamino Firing Range, ran through execVM on group's init:

 

This method is not 100% reliable and may hang on a loop. Read notes below.

Quote

private _group = _this;
private _posa = getPos (leader _group);

private _posz = [_posa # 0, _posa # 1, 0];

_group setVariable ["calcpath", []];

 

//wheeled_APC = back roads
//man = no roads
//car = main roads
isNil{
    private _obj = calculatePath ["wheeled_APC","safe",[2832.9,5927.79,0],[6457.89,5299.79,0]];

    _obj setVariable ["calcpathgroup", _group];

    _obj addEventHandler ["PathCalculated",{
        params ["_agent", "_path"];

        private _group = _agent getVariable "calcpathgroup";

        if ((_group getVariable "calcpath") isEqualTo []) then{
            _group setVariable ["calcpath", _path];
        };
    }];
};

waitUntil {!(_group getVariable ["calcpath", []] isEqualTo [])};

private _path = _group getVariable "calcpath";

//Path forward
{
    //Create waypoints
    private _wp = _group addWaypoint [_x, 0];
    _wp setWaypointType "MOVE";
}forEach _path;

 

Notes:

While this setVariable, waitUntil getVariable is not the most reliable method (although no more fails so far 🙂👍) still, i came up with some conclusions about this command(s):

  • Passed positions to calculate path must be on road if you're finding path for "wheeled_APC", "car" or "tank".*
  • Only "man" accepts non-road positions. Water and air paths were not tested.*
  • If you don't pass a position on road, and running multiple groups (or maybe just one), it will often fail and no path is found. waitUntil will run indefinitely.*
  • If you pass _posa or _posz as on example, even if the unit (man or car) is on road it may fail! (Need confirmation with every vehicle on road)*

*Tested with "safe" behaviour only.

 

Edit: Agent does not have to be global and addWaypoint does not need to be spawned as i stated before.

 

 

Edited by RCA3
Updated code and notes.
  • Like 2

Share this post


Link to post
Share on other sites
15 hours ago, RCA3 said:

Here's one method "apparently" working with 50 groups (100 AI) from one corner of Stratis to the other, ran through execVM on group's init:

Way to persevere man.  Very interesting video of a "mass exodus", I can see refugees streaming down roads in a mission.  Funny how they tard out on the bridge (I guess a bridge is like a building with LOD paths).

 

Are you experimenting to understand calculatePath usage, or do you have a specific purpose in mind?

  • Thanks 1
  • Haha 1

Share this post


Link to post
Share on other sites

You should see them on Tanoa bridges. I'm becoming more of an author-of-workarounds than mission maker, these days.

  • Haha 2

Share this post


Link to post
Share on other sites
16 minutes ago, Tankbuster said:

You should see them on Tanoa bridges. I'm becoming more of an author-of-workarounds than mission maker, these days.

Welcome to the club. I thought that for an age!

  • Like 2
  • Haha 2

Share this post


Link to post
Share on other sites
49 minutes ago, Tankbuster said:

You should see them on Tanoa bridges. I'm becoming more of an author-of-workarounds than mission maker, these days.

F***in' A bro, I feel you.

  • 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

×