WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   AddOn Help/Support (https://www.wowinterface.com/forums/forumdisplay.php?f=3)
-   -   Distance formula to calculate speed between two points (https://www.wowinterface.com/forums/showthread.php?t=41795)

Vlad 11-12-11 08:58 AM

Distance formula to calculate speed between two points
 
I've spotted the InFlight thread about posting distance results of flights, so I wrote a script that parses the DBC data to extract this information, but I am stuck making this function properly:

Code:

// get delay between two points on a map and the movement speed modifier
function getDelay($from, $to, $speed) {
  $time = 0;
  if(is_array($from) && is_array($to)) {
    $m1 = $from['mapId']; $x1 = $from['x']; $y1 = $from['y']; $z1 = $from['z'];
    $m2 = $to['mapId'];  $x2 = $to['x'];  $y2 = $to['y'];  $z2 = $to['z'];
    $dx = abs($x1 - $x2); // TODO: are these correctly calculated?
    $dy = abs($y1 - $y2); // TODO: are these correctly calculated?
    $R = 1000; // NYI: mean radius of world (mapId)
    $a = pow(sin($dx/2), 2) + cos($x1)*cos($x2)*pow(sin($dy/2), 2);
    $c = 2*atan2(sqrt($a), sqrt(1-$a));
    $d = $R * $c;
    $S = 10; // NYI: speed constant that will be modified by $speed (%)
    $time = $d/($S*$speed);
  }
  return $time;
}

Basically, I have to calculate the distance between the two points (mapId1,x1,y1,z1) and (mapId2,x2,y2,z2) and I have the speed modifier here (100%, 150%, e.g.) but my speed constant and the radius of the mapId will be a challenge, anyone got any help on this matter? :(

If I get this to work sure I'll post source and best of all no flight addon will have to calculate on the fly, the time it will take to fly the path! One can in advance of a patch calculate the data from the DBC themselves and produce a LUA database with all the exact timers, cool right?

Taryble 11-12-11 01:19 PM

That would work, assuming that all flight paths are perfectly straight lines.

Seerah 11-12-11 01:34 PM

The way that InFlight and other timers work is by users recording how long it takes to fly from point A to point B. If a new flight is not in the addon's database, then it just measures how long it takes and stores that for next time.

SDPhantom 11-12-11 01:39 PM

If you have absolute coordinates, you don't need MapID. You're also using a bunch of unneeded trig functions.

PHP Code:

function getDistance($x1,$y1,$z1,$x2,$y2,$z2,$speed)
    return 
sqrt(pow($x1-$x2,2)+pow($y1-$y2,2)+pow($z1-$z2,2))/$speed;
end 

Note: $speed needs to be in the same units as the coordinates, this means since the absolute coordinates of a map are measured in yards, $speed needs to match it too. For 100% speed, this would be a value of 7.

Seerah 11-12-11 01:40 PM

(Don't forget that we do not have access to z-coordinates.)

Vlad 11-12-11 01:41 PM

Thing is if the path isnt a straight line then you add more nodes and make the game slightly wobble (so it's not instant turns) but knowing the distances and angles between two coordinates would also allow you to figure out this wobble and include it in the time delay calculation, so you can achieve calculating the arrival time trough a path of nodes using their distances between each other.

For now my problem is that the paths have mapId relative coordinates so I have to figure out how big let's say northrend is, then outlands, e.g. Looking at MapDataLib for some info but havent gotten a proper formula, yet.

Anyway, there are advantages to calculating the times liek this, for once you can get all times without having to fly yourself to "time" it. :)

*Edit*

Saw your post SDPhantom, thanks. Gonna work it in, hehe. Yeah, I'm a bit unclear about the formulas, hence they look messy. ;)

The coordinates in the DBC are raw, but not sure if it maters the size of the map, I guess not as long we dont fly across one map to the other (like to azuremyst but thats another problem to figure later on, hehe).

Seerah 11-12-11 01:43 PM

I don't understand what you mean by "nodes" and "wobble"?

SDPhantom 11-12-11 01:57 PM

Quote:

Originally Posted by Vladinator (Post 247196)
Thing is if the path isnt a straight line then you add more nodes and make the game slightly wobble (so it's not instant turns) but knowing the distances and angles between two coordinates would also allow you to figure out this wobble and include it in the time delay calculation, so you can achieve calculating the arrival time trough a path of nodes using their distances between each other.

For now my problem is that the paths have mapId relative coordinates so I have to figure out how big let's say northrend is, then outlands, e.g. Looking at MapDataLib for some info but havent gotten a proper formula, yet.

Anyway, there are advantages to calculating the times liek this, for once you can get all times without having to fly yourself to "time" it. :)

*Edit*

Saw your post SDPhantom, thanks. Gonna work it in, hehe. Yeah, I'm a bit unclear about the formulas, hence they look messy. ;)

The coordinates in the DBC are raw, but not sure if it maters the size of the map, I guess not as long we dont fly across one map to the other (like to azuremyst but thats another problem to figure later on, hehe).

Internally, all objects are rendered at coordinates based on each continent. I'm not entirely sure what units such coordinates are based off of. I wouldn't automatically assume that it's still in yards.

Quote:

Originally Posted by Seerah (Post 247197)
I don't understand what you mean by "nodes" and "wobble"?

I'm guessing "node" is each point that makes up the actual flight path and "wobble" is the method of which the game smooths out each turn by imposing a limit to the turning rate. However, the turn rate limit may just be enforced by adding more points in a turn to make it look smooth.

Vlad 11-12-11 02:08 PM

It's a bit hard to explain, so I'll show some examples of what I mean;

TaxiNodes.dbc contains the columns:
TaxiId, mapId, x, y, z, name, ...

TaxiPath.dbc contains the columns:
PathId, fromTaxiId, toTaxiId, cost

TaxiPathNode.dbc contains the columns:
PathNodeId, PathId, counter, mapId, x, y, z, ...

Combining these information tables you can combine a start and a destination, for example in TaxiNodes.dbc Stormwind is #2 and Goldshire is #582.

Then you check TaxiPath.dbc if you have a PathId for a path fromTaxiId=2 and toTaxiId=582, if not then that taxi path does not exist.

If you do on the other hand, you look the nodes in the path (the mount follows these node by node) in TaxiPathNode.dbc where you look up all PathNodeId where PathId=TaxiPath.PathId and you get a list where counter goes from 0 up to the last node (SW->GS has 16 nodes along the flight path).

Each flight position has coordinates, they are relative to the map and we know the mapId in case we need to translate coordinates (i.e. flying from one map to the other, e.g. maybe it affects the distance calculations, not sure, maybe not).

Anyway, mathematically you can iterate a path of many nodes and each step you take you compare this with the previous (or next, depending how you program it) and get a distance difference by putting the coordinates in a formula, then if you know how fast you are moving you can calculate the time between each node and sum them all up for the total travel time from start to finish.

The only problem so far is the possibility of a "wobble", like this:

Fig. 1 is how the math would calculate distances, straight lines from one point to the other. Fig. 2 is how it feels in the game, you don't fly and instantly turn once you hit a node, instead the game does some sort of wobble to make the transition smooth between nodes.

TaxiNodes = positions you can land and take off
FlightNodes/(I call them nodes in this post) = the orange dots in between the air, not visible but you go from one to the next like waypoints.

*Edit*

SDPhantom the coordinates are on this form (one random line from both files that contain coordinates):
2,0,-8841.05957031,489.656005859,109.607002258,"Stormwind, Elwynn",0,541,1,0.00998003967106,0.0101744187996,
35,6,0,0,-8852.65039063,496.459991455,111.040000916,0x0,0,0,0,
You have the mapId (0 in this case) and the coordinates, it does look like continent coordinates, yes.

*Edit 2*
Just figured I'd put an example output so far, the time is about right for this specific path, but need to find the speed value, it may be variable or constant if lucky. At the moment the speed was set to 30.33... but need to test with more FP to see if it applies to them or not, I think not because of this wobble I mentioned in the post. :(
Quote:

Flying path #557 for 1020 copper:
- #128; Shattrath, Terokkar Forest
- #121; Allerian Stronghold, Terokkar Forest
- parsing nodes along path...
-> #start to #14252 (+0.15 seconds)
-> #14252 to #14251 (+0.71 seconds)
-> #14251 to #14250 (+1.48 seconds)
-> #14250 to #14249 (+2.33 seconds)
-> #14249 to #14248 (+2.47 seconds)
-> #14248 to #14247 (+3.21 seconds)
-> #14247 to #14246 (+5.81 seconds)
-> #14246 to #14245 (+13.83 seconds)
-> #14245 to #14244 (+7.16 seconds)
-> #14244 to #14243 (+4.55 seconds)
-> #14243 to #14242 (+4.87 seconds)
-> #14242 to #14241 (+6.92 seconds)
-> #14241 to #14240 (+4.93 seconds)
-> #14240 to #14239 (+5.49 seconds)
-> #14239 to #14238 (+5.59 seconds)
-> #14238 to #14237 (+3.15 seconds)
-> #14237 to #14236 (+1.66 seconds)
-> #14236 to #end (+0.06 seconds)
=> arrived destination after 74.36 seconds!

SDPhantom 11-12-11 02:30 PM

Quote:

Originally Posted by Vladinator (Post 247202)
Just figured I'd put an example output so far, the time is about right for this specific path, but need to find the speed value, it may be variable or constant if lucky. At the moment the speed was set to 30.33... but need to test with more FP to see if it applies to them or not, I think not because of this wobble I mentioned in the post. :(

In my experience, the speed of a flight path does vary and is based on the departing point. This seems to decide on what kind of mount you ride on for the duration of the flight and through which, how fast it goes.

In Azeroth, there are only a handful of such mounts it chooses on, which are faction-based and mostly fly the same speed. I think Outland is the same. Where you really see a difference is in Northrend. For example, one flight path would give you a gyrocopter to ride on which is the slowest among the list, while another would give you a dragon mount, which are the fastest.

Talyrius 11-12-11 03:51 PM

Quote:

For example, one flight path would give you a gyrocopter to ride on which is the slowest among the list, while another would give you a dragon mount, which are the fastest.
I find it hard to believe that Blizzard would introduce speed variance on fixed flight paths like you're suggesting.

Have you actually verified this or is this a conclusion based on your observations of how fast it feels? I hear people comment on how some mounts feel slower or faster relative to other mounts all the time, but this isn't actually the case. How fast something feels is an imprecise method of measurement.

Dridzt 11-12-11 05:08 PM

Try flying Sholazar Basin, it's absolutely verified.

SDPhantom 11-12-11 06:31 PM

Quote:

Originally Posted by ForeverTheGM (Post 247210)
I find it hard to believe that Blizzard would introduce speed variance on fixed flight paths like you're suggesting.

Have you actually verified this or is this a conclusion based on your observations of how fast it feels? I hear people comment on how some mounts feel slower or faster relative to other mounts all the time, but this isn't actually the case. How fast something feels is an imprecise method of measurement.

It's gathered from the GetUnitSpeed() API function. I had it running on a version of my personal HUD addon while playing.

Vlad 11-12-11 08:28 PM

Must be some way to do this from the DBCs considering they define the distances and flight related paths...

*Edit*

Good news, tested it flying between SW, Goldshire and Eastvale and the timers expected are about right, only that in-game there can be up to a second delay when you click and actually start to fly, e.g. or between path transitions (i.e. sw to goldshire then it has to hop you on from goldshire to eastvale, that transition can take enough time to add a couple of seconds to the total timer from start to finish if you fly and jump many different paths).

Going to make a function to iterate trough the various possible paths in-game, that exists of course, then store it in a file and check with the current InFlight.lua data and see how much off I am, hehe. If lucky and it's only some seconds differences then it may be my speed constant that needs changing, or changing depending on the path, there are some flags I am not sure what are on taxinodes so if lucky they hold the answer to the speed problem. :)

*Edit 2*
These are the times for single flights only (no connections):
http://pastebin.com/PJLHijdG (from, to, copper, time)
I've looked in the inflight data and must say it's scary how similar the times are, only a few weird entries like Sentinel Hill to Stormwind is 25 sec on inflight while around 80 on the calculations. :P
For chained flights one has to think about the start->node1 and nodeN->end times and skip them on paths in between, i.e. if you fly Stormwind -> Duskwood -> Blasted Lands one would have to skip the nodeN->end (landing) time between Stormwind and Duskwood, Duskwood and Blasted Lands you need to skip both launch and landing, and at the end you must skip the launch->node1 while include the nodeN->landing times to get it most accurate as you can.
In the DBC the taxi path names are localized so it's a bit tricky to make it easy to work on many locales, considering the ID in the DBC are not accessible trough game API (I think they should make it tough, hehe).

Anyway, these are my findings so far. I'll release my PHP script for the data management and such soon, it's not a big deal, and it's actually a bit noobish in layout. :( Made it mainly to extract data from DBCs (actually their CSV files after using another program to convert the DBCs) to begin with.

About making the flightmaps tough, this shouldn't be too hard:
1. We have a list of all from and to paths, so all you have to do is scan this array of data and check "I am at X, when is from=X and store the to value in a table with a index of X" thus you end up with for example: {[2]={5,6,8}} where at node 2 you have access to nodes 5, 6 and 8. Then you can do a debt query and go further down, check where does 5 go to, where do 6 go to, e.g. When at the FP in-game you know where you start and you know where you want to go, and the game marks the path so you know the nodes in between, so with something smart you can recursively find these path names and by having some sort of library to convert the names into ID's for example, you can extract the times from the database above and sum up the different times.
I realize you loose the launch->node1 and nodeN->landing times but assume 1+-2 seconds differences in the mathematical from the actual version.
Besides, latency also plays a role, if you have 500ms you will notice slight alteration in the times anyway, you can't get the times 100% accurate, only estimates so it's not a bad idea to use the raw data to generate the flight times I think. :)

Sorry for blocks of text.

Is there any point me writing this btw? I got the impression someone else is benefiting from this information, maybe not, maybe it's just me...

Torhal 11-13-11 04:42 PM

The flightpath speeds are constant per flightpath: The Sholazar flightpath is substantially slower than others.

Vlad 11-13-11 09:04 PM

Each taxi location has a creature ID (some are 0, not sure what that means really...) anyway these are the current creature ID's:
http://pastebin.com/DHyu3BZY

Somehow one has to extract the information about their speeds from the server, because the DBC do not contain this information.

For example: http://db.mmo-champion.com/c/54271/

SDPhantom 11-14-11 05:02 AM

Quote:

Originally Posted by Torhal (Post 247255)
The flightpath speeds are constant per flightpath: The Sholazar flightpath is substantially slower than others.

To avoid confusion and restate what I said earlier with the same clarity... Flight path speeds are determined from the original departure point. This means even when chaining paths to reach your destination, your speed remains constant between hops. Your mount/speed never changes from start to finish. This also means it is entirely possible, between two direct points, to fly faster in one direction than the other.

Torhal 11-14-11 09:09 AM

That's what I was trying to express, but I was a bit terse about it so I failed miserably. :D

Vlad 11-14-11 03:46 PM

1 Attachment(s)
If lucky the speeds can be read from the creature when flying... but considering when you mount you can't directly query the creature itself, this will be a bit hard, or maybe it's just a creature ID for the visuals, the speeds may be hardcoded in the exe maybe, since it's a bit unlikely that they are in the DBC, but maybe you are more awesome then me, so I put the files in a zip if you like to peak at the source data. :)

SDPhantom 11-14-11 08:17 PM

It's readable with a call to GetUnitSpeed("player") while on a taxi.

Vlad 11-15-11 08:44 PM

It's not quite on topic, but let me ask you smart guys;

This is the data:
A -> B
B -> C
C -> D
E -> C
A -> E
B -> A
C -> B
C -> A
A -> C

You see, if you wish to go from A to D you can go:
(1) A->B->C->D
(2) A->C->D
(3) many others involving cycles like A->C->B->A->C->D and so forth...

In any case, I have this system in MySQL:
{PrimKey, X, Y} where PrimKey is an integer, X and Y are the node values. For example A->B is {1, A, B}, then B->C becomes {2, B, C} and so forth.

This is graph theory, traversal of graphs but considering there are cycles this makes it a bit tricky.

I have to make a class i.e. "Map" to help me keep order of who comes and goes to who. This way if I want to go from A to D I can return a list where I get various paths leading to D without the backtracking (A->C->B->A->C->D e.g.) and it shouldn't stuck looping indefinitely.

Do you have some ideas how I should structure this class?

I was thinking something along the lines of:
class Map {
nodes = array();
addNode(node) {
addChild(getParent(node::letter), node) // find A in nodes then add this node as that parents child, if not then add the child as a new root-node with node::letter as index key
}
getRoutes(start, end) {
// traverse the nodes, find any paths starting at start and ending at end, paths not leading to the end are ignored, this I reckon will be a recursive function
}
}

Very rough, maybe someone has a better idea or a tip like example code they know of on the net. :P

SDPhantom 11-16-11 01:52 AM

A method I could think of is to have it scan out, branching off every time it has a choice based on direction from the origin point. I've had experience in writing functions that run recursively though data without the need to call itself. This usually involves building and managing your own data in a stack-like data structure. You end up using more memory instead of increasing your call stack, which is the best way to avoid stack overflows. It'll take a while to write it all from scratch. I'm assuming this would be in PHP?

Vlad 11-16-11 02:30 AM

Indeed, php. :(

SDPhantom 11-16-11 03:34 PM

I'm looking into writing some code that'll allow you to add paths with a cost metric and the pathfinding AI will choose the lowest cost route. To conserve processing time, it'll "give up" on a path if its cost exceeds that of a route it already discovered.

This method will allow you to customize what you use for a path's cost metric, whether it's the copper cost, distance, or even number of hops. The first two should be easy to figure out, but to do hops, you'll need to set the cost of all paths to a single number greater than zero, like 1.

I may have the pathfinding AI accept a max cost argument that it'll automatically "give up" on if the cost is exceeded.

SDPhantom 11-16-11 06:03 PM

I have a working prototype running and here's the debug info that it's printing.
The following calls were made to generate this.
Code:

addPath("A","B",1);
addPath("A","C",1);
addPath("A","E",1);
addPath("B","A",1);
addPath("B","C",1);
addPath("C","A",1);
addPath("C","B",1);
addPath("C","D",1);
addPath("E","C",1);

findRoute("B","E");


Path Data:
Code:

Create: A>B(1)
Add: A>C(1)
Add: A>E(1)
Create: B>A(1)
Add: B>C(1)
Create: C>A(1)
Add: C>B(1)
Add: C>D(1)
Create: E>C(1)

Array
(
    [A] => Array
        (
            [0] => Array
                (
                    [0] => B
                    [1] => 1
                )

            [1] => Array
                (
                    [0] => C
                    [1] => 1
                )

            [2] => Array
                (
                    [0] => E
                    [1] => 1
                )

        )

    [b] => Array
        (
            [0] => Array
                (
                    [0] => A
                    [1] => 1
                )

            [1] => Array
                (
                    [0] => C
                    [1] => 1
                )

        )

    [C] => Array
        (
            [0] => Array
                (
                    [0] => A
                    [1] => 1
                )

            [1] => Array
                (
                    [0] => B
                    [1] => 1
                )

            [2] => Array
                (
                    [0] => D
                    [1] => 1
                )

        )

    [E] => Array
        (
            [0] => Array
                (
                    [0] => C
                    [1] => 1
                )

        )

)


Routing Steps:
Code:

Routing B>E
Iterating Stack: 0@0=B>A 0+1=1
Push Stack 1
Iterating Stack: 1@0=A>B 1+1=2
Iterating Stack: 1@1=A>C 1+1=2
Push Stack 2
Iterating Stack: 2@0=C>A 2+1=3
Iterating Stack: 2@1=C>B 2+1=3
Iterating Stack: 2@2=C>D 2+1=3
Pop Stack 2
Iterating Stack: 1@2=A>E 1+1=2
Route Found

Array
(
    [0] => 2
    [1] => B
    [2] => A
    [3] => E
)

Pop Stack 1
Iterating Stack: 0@1=B>C 0+1=1
Push Stack 1
Iterating Stack: 1@0=C>A 1+1=2
Cost Exceeded
Iterating Stack: 1@1=C>B 1+1=2
Cost Exceeded
Iterating Stack: 1@2=C>D 1+1=2
Cost Exceeded
Pop Stack 1
Pop Stack 0


Returned Route:
Code:

Array
(
    [0] => B
    [1] => A
    [2] => E
)


SDPhantom 11-16-11 06:25 PM

Polished off a few checks and removed the debug code. Here's the prototype.
PHP Code:

$paths=array();

function 
addPath($src,$dst,$cost=1){
    global 
$paths;

    if(
$src==$dst || $cost<0) return NULL;
    if(
$paths[$src]){
        foreach(
$paths[$src] as $i) if($i[0]==$dst) return false;
    }else
        
$paths[$src]=array();

    
$paths[$src][]=array($dst,$cost);
    return 
true;
}

function 
findRoute($src,$dst,$maxcost=NULL,$maxhops=NULL){
    global 
$paths;

    if(!
$paths[$src]) return NULL;

    
$found=false;
    foreach(
$paths as $i) foreach($i as $j) if($j[0]==$dst){$found=true;break;}
    if(!
$found) return false;

    
$pstack=array(array($src,0,0));
    while((
$id=count($pstack)-1)>=0){
        
$ptr=&$pstack[$id];
        if(
$node=$paths[$ptr[0]][$ptr[1]++]){
            
$cost=$ptr[2]+$node[1];
            if(
$maxcost===NULL || $cost<=$maxcost){
                if(
$node[0]==$dst){
                    
$maxcost=$cost;
                    
$route=array();
                    foreach(
$pstack as $i$route[]=$i[0];
                    
$route[]=$dst;
                    
array_pop($pstack);
                }elseif(
$paths[$node[0]] && ($maxhops===NULL || ($id+1)<$maxhops)){
                    
$unique=true;
                    foreach(
$pstack as $i) if($i[0]==$node[0]){$unique=false;break;}
                    if(
$unique)
                        
array_push($pstack,array($node[0],0,$cost));
                }
            }
        }else
            
array_pop($pstack);
    }

    return 
$route?$route:false;


Notes:
addPath() returns true on success, false on duplicates, and NULL on error.
findRoute() returns an array on success, false if no path found, and NULL on error.

Vlad 11-16-11 08:19 PM

Wow SDPhantom, you really put effort into this code, thanks!

I got the basic idea, just trying to sort off cycles now, as it gets stuck looping in a circle thinking it goes forward. :D I need to add a "visited" check to skip going where we've already been I reckon.

SDPhantom 11-16-11 08:52 PM

Strange, can you post a copy of the paths you're registering? When it checks a path, it looks back into the stack to see if the node isn't already in there. With a bigger data set, it would often recheck paths again when going back up the stack. You can try setting the maxcost to limit how far it runs away with this.

Vlad 11-16-11 10:35 PM

http://pastebin.com/e0LfewY1

For example if I do this:
findRoute(2, 15);

The output of the id is this:
Code:

0>1>1>2>2>2>3>3>3>3>4>4>4>4>5>5>5>5>5>6>6>7>7>7>6>5>6>6>6>6>5>4>5>6>7>7>7>7>7>7>8>8>8>8>7>6>6>5>5>4>5>6>6>6>7>7>8>9>9>10>10>11>11>11>12>12>12>12>13>13>14>14>14>14>15>15>16>16>16>16>16>17>17>18>19>20>20>21>21>22>22>23>24>25>25>26>26>26>26>27>27>27>28>28>28>29>29>29>30>31>31>31>31>30>30>29>28>27>27>28>29>29>30>31>31>31>31>30>30>30>29>28>28>28>27>...
It keeps repeating after the dots... going back to 26 then up to 31 and back to 26, e.g. It's a bit odd indeed, are you getting that too?

SDPhantom 11-17-11 03:56 AM

The stack ID only reflects the size of the stack at the time, it'll always be going up and down until it's all done. It's pretty much equal to how many hops it's at in its current path.

SDPhantom 11-17-11 03:41 PM

I looked at the DBC data over and discovered that no paths lead to #15. I added in a check for this before it starts pathing and an additional maxhops argument. I would suggest using it to cut down on processing time. You may use NULL to bypass the maxcost argument.

For example, this'll trace an alliance route from Booty Bay to Light's Hope Chapel with a max of 10 hops.
Code:

findNode(19,67,NULL,10);
The code in my previous post has been updated with these changes.

PS: You should only load in paths accessible to a specific faction to help in processing if by chance it's queried for a route cross faction. It can also wander over into cross faction routes if it hits shared paths. It seems the value following the unknown horde/alliance IDs is indeed a 3-bit faction flag. Bit 1 is alliance and bit 2 is horde. I see bit 3 set in a few paths, but it's unknown what that means at this point.

Vlad 11-17-11 05:02 PM

Hmm, really? Maybe I used a node no longer accessible, should have used the lighthope chapel one, sorry for my mistake too, kind of set you on the wrong path.

Yes, you are right about the faction thing, should not mix them up.

*Edit*

Very nice mate, couldn't have done this all by myself -tough I should, had graph theory in Java a year ago. :(

Anyway, got it working on my end as well, made a class for it and it only reads in paths that are accessible for the faction when I am flying around in my virtual WoW. ;)

*Edit 2*

I ran some calculations for 10 paths from Stormwind, the results were (time in HH:MM:SS):
Code:

Stormwind, Elwynn -> Sentinel Hill, Westfall takes 00:01:11
Stormwind, Elwynn -> Lakeshire, Redridge takes 00:01:50
Stormwind, Elwynn -> Ironforge, Dun Morogh takes 00:03:32
Stormwind, Elwynn -> Menethil Harbor, Wetlands takes 00:05:28
Stormwind, Elwynn -> Thelsamar, Loch Modan takes 00:05:13
Stormwind, Elwynn -> Darkshire, Duskwood takes 00:01:53
Stormwind, Elwynn -> Refuge Pointe, Arathi takes 00:06:53
Stormwind, Elwynn -> Booty Bay, Stranglethorn takes 00:03:15
Stormwind, Elwynn -> Aerie Peak, The Hinterlands takes 00:07:29
Stormwind, Elwynn -> Nethergarde Keep, Blasted Lands takes 00:02:53

Checking the InFlight data that contains the proper times (+-1/2 seconds difference, since latency has something to say on the arrival time as well), in any case these were the differences in seconds:
Code:

Stormwind, Elwynn -> Sentinel Hill, Westfall takes (71-73) -2
Stormwind, Elwynn -> Lakeshire, Redridge takes (110-113) = -3
Stormwind, Elwynn -> Ironforge, Dun Morogh takes (212-215) = -3
Stormwind, Elwynn -> Menethil Harbor, Wetlands takes (328-233) = 95
Stormwind, Elwynn -> Thelsamar, Loch Modan takes (313-212) = 101
Stormwind, Elwynn -> Darkshire, Duskwood takes (113-116) = -3
Stormwind, Elwynn -> Refuge Pointe, Arathi takes (413-375) = 38
Stormwind, Elwynn -> Booty Bay, Stranglethorn takes (195-198) = -3
Stormwind, Elwynn -> Aerie Peak, The Hinterlands takes (449-412) = 37
Stormwind, Elwynn -> Nethergarde Keep, Blasted Lands takes (173-176) = -3

Those that are heavily out of mark like Menethil Harbor, Thelsamar, Refuge Pointe, Aerie Peak, those I think are because of my coding of the faction check, if not then something else must have gone wrong, since the others are up to 3 seconds quicker than what InFlight says the times are, 3 seconds is not bad at all considering it's all calculated trough formulas and not stopwatch. ;)

With some fine tuning like adding delay because of the "wobble" effect (large angles, high distances, create a slight deviation in the distance calculation, this is not yet addressed in the code), and proper faction checks to allow neutral paths when flying as any faction but restrict the path finding to either Alliance or Horde and avoid mixing those.

Perhaps these huge deviations may be due to result of flights going quicker than the constant speed I calculate with (30+1/3), maybe those paths used quicker flight speeds, so this also has to be added in the code.

This was my "report" on the matter for now, when this is done I'll share my code for anyone to use that needs to calculate taxi flight times. :P

Seerah 11-17-11 08:44 PM

Do your calculations account for when the taxi circles before landing?

Vlad 11-17-11 09:16 PM

Yes it should, hard to tell atm because I need to implement the various speeds on some flightpaths, hehe.

For many regular gryphon based flightpaths with regular speeds the calculations return answers within 3 seconds of the InFlight data, I guess the last 3 seconds are due to latency; it takes a up to a second to start flying and landing and some minor delays due to wobble effect or when jumping from a node to node in general.

I think Ironforge may be the cause of the weird timers on my end, probably because the game does not fly in the city when flying on a connected path, it skips some nodes that I include in the calculations most likely, need to research more. :)

Seerah 11-17-11 10:21 PM

Ah, yes, that would definitely be a contributing factor. SW, too.

Vlad 11-19-11 02:22 PM

Something I noticed about GetUnitSpeed:

The API returns different values but very small changes, decimals only.

Still, at long paths this may change the time up to 10 seconds at worst, maybe this has something to do with lag compensation?

I.e. if the average player ms is 500 then the game would make up for the time lost in between node connections (i.e. sw->goldshire->redrige), each "->" jump would need to be confirmed with the server so if the mount visually flies quicker and the client comes at the last node and requests the next path, it has accounted for the slight delay ocuring so you wouldn't loose time.

Somehow it doesn't make any sense because the location of the player is anyway decided by the server, that explains why I've sometimes seen me land earlier than I should by having my flight just teleport me the last 40 yards instead of flying and landing like it should have.

The gryphons (creature 541) flies between 30.1 to 30.4 so any decimals in between, very weird and hard to account for when flying, thus even tracking the time with a stopwatch would always return 1-3 seconds differences between flights due to this randomness...

Still, some seconds off the mark is not a big deal considering you still know you got over 13 minutes of flying if you want to fly from Booty Bay to Eastern Plaguelands. ;)

Saiket 11-25-11 07:21 PM

4 Attachment(s)
I spent a weekend trying to figure out the flight-path mechanics, and while I did come pretty close to accurately modeling them, I'm stumped by a few issues. Since I doubt I'll make anymore progress without a big time commitment, here's what I've found so far:
  1. WoW smooths the paths between TaxiPathNode points using splines—specifically, Catmull-Rom splines. I wrote a test addon so I could experimentally compare expected and measured flightpaths, and Catmull-Rom seems 100% accurate.

    Cyan line is the expected path, red line is the measured path, alternating yellow and purple sets of dots mark joined path splines' control points, yellow gridlines are map chunk boundaries, and the red crosshair centers on the player.
  2. For multi-part flights, WoW takes the shortest combination of paths, unless a direct route is available. The "length" of a path is the length of the Catmull-Rom spline in 3D space, found through integration.
  3. Where two paths join together, WoW seems to dynamically strip away spline control points between them that would make too sharp a turn. I didn't attempt to reverse engineer the algorithm, since it would just be a bunch of guesswork and tweaking without WoW's source code available. My test addon defines a function GetSkippedNodes in case anyone wants to attempt to implement this properly. For now, it returns placeholder values 1,1 to skip one innermost point from each joined path. Here are a few examples where paths join incorrectly:

    While I was taking screenshots for this post, I noticed that last example where WoW actually makes a tight turn. Who knows.
  4. I couldn't find any way to estimate flight-path speeds. It's definitely not constant across all paths, and instead seems to be determined by the node you depart from. The NPC ID of your flight-path mount (from TaxiNodes) works the same way, but I don't know if your mount affects your speed here. Even if it does, I couldn't find a lookup for NPC speed in my cache files or the DBCs.

    I have noticed that flight-path speed appears to vary, but GetUnitSpeed doesn't reflect it. I assume any visual speed change is just rubber-banding when you periodically synchronize your flight-path progress with the server.

Overall it's still pretty inaccurate because of lag, unknown speed, and the path joint issue. Oh well, it was still a fun project. :)

My test mod is attached if anyone wants to play with it. "/taxi" opens the grid, and you can navigate around sort of like Google Maps. If you talk with a flight master while the grid is open, hovering over nodes will plot their expected paths.

Vlad 11-25-11 07:34 PM

Very informative post, thanks for sharing your findings!

Very interesting, catmull-rom splines, haven't heard of that until now, gotta look into this!


All times are GMT -6. The time now is 10:47 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI