swordlegend / recastnavigation

Automatically exported from code.google.com/p/recastnavigation
zlib License
0 stars 0 forks source link

dtNavMeshQuery::init( navMesh, tooFewNodes ); #145

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Is there any well to tell that a path find failed because the dtNavMeshQuery 
was initialised with too few nodes?

Ta,
Neil

Original issue reported on code.google.com by armstron...@gmail.com on 16 Nov 2010 at 6:29

GoogleCodeExporter commented 9 years ago
Currently no. I would like to find a good way to return following cases:
- out of nodes
- return buffer too small
- end polygon could not be reached

I think I have several options here:
- use the return code, making it a bitfield (success/fail + reason). (may run 
out of bits, annoying to test success)
- add additional parameter (annoying, bloats API)
- add additional function which returns more information about last call like 
opengl get error (kinda most flexible, don't like to store additional state)

Any thoughts on those or other ideas?

Original comment by memono...@gmail.com on 21 Nov 2010 at 3:26

GoogleCodeExporter commented 9 years ago
Why not just extend the dtStatus enum to deal with the additional failure cases?

You could do this:

enum dtStatus
{
    DT_FAILURE = 0,             
    DT_FAILURE_DATA_MAGIC,
    DT_FAILURE_DATA_VERSION,
    DT_FAILURE_OUT_OF_MEMORY,
    DT_FAILURE_MAX,
    DT_SUCCESS,
    DT_SUCCESS_BUFFER_TOO_SMALL,
    DT_SUCCESS_NO_PATH,
    DT_SUCCESS_OUT_OF_NODES,
    DT_SUCCESS_MAX,
    DT_IN_PROGRESS
};

Clients can check for DT_SUCCESS->DT_SUCCESS_MAX for all success cases, and 
likewise for failures.

If you don't like this then the bitfield option seems like the a good choice. 
You could mix a bitfield with an error id. So, for example, the last 3 bits 
represent SUCCESS, FAILURE and IN_PROGRESS and the rest of the status is an 
error code. Checking for success/failure would simply be:

dtStatus status = callDetourFunc();
if ( status & DT_SUCCESS )
{
    // Wahoo!
}
else if ( status & DT_FAILURE )
{
    // Boo!
}

enum dtStatus
{
    DT_FAILURE = 1<<29,
    DT_SUCCESS = 1<<30,
    DT_IN_PROGRESS = 1<<31,
    DT_FAILURE_DATA_MAGIC = 1 + DT_FAILURE,
    DT_FAILURE_DATA_VERSION = 2 + DT_FAILURE,
    DT_FAILURE_OUT_OF_MEMORY = 3 + DT_FAILURE,
    DT_SUCCESS_BUFFER_TOO_SMALL = 1 + DT_SUCCESS,
    DT_SUCCESS_NO_PATH = 2 + DT_SUCCESS,
    DT_SUCCESS_OUT_OF_NODES = 3 + DT_SUCCESS
};

You can still support millions of unique error codes, but you get the 
convenience of simple success/failure checks. Switch statements work without 
needing to mask off any bits.

Original comment by armstron...@gmail.com on 22 Nov 2010 at 9:19

GoogleCodeExporter commented 9 years ago
The three success cases can all theoretically happen at the same time. Error 
codes tend to be solo.

 Also, in order to find good sweet spot of number of nodes, you might need better statistics, like what is the average used node count and how often you run out of them. It might make sense to keep track of this statistics too.

Also, the user logic could try to handle the out-of-nodes case by replaning 
when the goal is reached.

I think I'll go for the return flags thing.

Original comment by memono...@gmail.com on 22 Nov 2010 at 10:13

GoogleCodeExporter commented 9 years ago
>>The three success cases can all theoretically happen at the same time
Ok yeah - I hadn't considered that. Going with flags is probably best then. The 
client will be able to "or" together dtStatus return values without losing 
info, which is cool...but, like you said, there's a chance you'll run out of 
flags? 

I guess you'll only ever be in a success, failure or in-progress state - so you 
could share the bits (i.e. 29 unique failure bits and 29 unique success bits - 
assuming 3 bits reserved for success/failure/in-progress flags).

Original comment by armstron...@gmail.com on 22 Nov 2010 at 10:48

GoogleCodeExporter commented 9 years ago
Yeah, my idea was to reuse bits depending on the higher level state.

In practice, I think I could use 2 bits to define the state (success, failure, 
in-progress) and use the 30 bits to either describe error code (or bits) or 
return value bits.

In that case the above code might become:

dtStatus status = callDetourFunc();
if (dtStatusSucceed(status))
{
    // Wahoo!
}
else if (dtStatusFailed(status))
{
    // Boo!
}

I think I'll let it simmer for few more days and try to implement it on Friday.

Original comment by memono...@gmail.com on 22 Nov 2010 at 12:02

GoogleCodeExporter commented 9 years ago
>>I think I'll let it simmer
Good plan. There's no right answer with returned error codes/flags etc. I 
normally start with a standard enum (i.e. unique error code) and then I find I 
need flags because I'm ending up with:

enum ErrCode
{
    Err_This,
    Err_That,
    Err_This_And_That <- Hmmm...not too bad if it's one or two occurrences, otherwise it gets nasty
};

dtStatusSucceed() and dtStatusFailed() sound like a good idea...makes it easier 
to change your mind later on without breaking client code.

Original comment by armstron...@gmail.com on 22 Nov 2010 at 12:28

GoogleCodeExporter commented 9 years ago
Fixed in R255, see 
http://digestingduck.blogspot.com/2010/11/detour-return-codes-take-2.html

Original comment by memono...@gmail.com on 26 Nov 2010 at 12:49