This commit is contained in:
ikpil 2023-04-28 23:22:09 +09:00
parent 89eb8554d9
commit 0620cdcd85
19 changed files with 217 additions and 217 deletions

View File

@ -246,8 +246,8 @@ namespace DotRecast.Detour.Crowd
// Find nearest position on navmesh and place the agent there. // Find nearest position on navmesh and place the agent there.
Result<FindNearestPolyResult> nearestPoly = navQuery.findNearestPoly(pos, m_ext, m_filters[ag.option.queryFilterType]); Result<FindNearestPolyResult> nearestPoly = navQuery.findNearestPoly(pos, m_ext, m_filters[ag.option.queryFilterType]);
var nearest = nearestPoly.succeeded() ? nearestPoly.result.getNearestPos() : pos; var nearest = nearestPoly.Succeeded() ? nearestPoly.result.getNearestPos() : pos;
long refs = nearestPoly.succeeded() ? nearestPoly.result.getNearestRef() : 0L; long refs = nearestPoly.Succeeded() ? nearestPoly.result.getNearestRef() : 0L;
ag.corridor.reset(refs, nearest); ag.corridor.reset(refs, nearest);
ag.boundary.reset(); ag.boundary.reset();
ag.partial = false; ag.partial = false;
@ -463,8 +463,8 @@ namespace DotRecast.Detour.Crowd
// TODO: this can snap agents, how to handle that? // TODO: this can snap agents, how to handle that?
Result<FindNearestPolyResult> nearestPoly = navQuery.findNearestPoly(ag.npos, m_ext, Result<FindNearestPolyResult> nearestPoly = navQuery.findNearestPoly(ag.npos, m_ext,
m_filters[ag.option.queryFilterType]); m_filters[ag.option.queryFilterType]);
agentRef = nearestPoly.succeeded() ? nearestPoly.result.getNearestRef() : 0L; agentRef = nearestPoly.Succeeded() ? nearestPoly.result.getNearestRef() : 0L;
if (nearestPoly.succeeded()) if (nearestPoly.Succeeded())
{ {
agentPos = nearestPoly.result.getNearestPos(); agentPos = nearestPoly.result.getNearestPos();
} }
@ -508,8 +508,8 @@ namespace DotRecast.Detour.Crowd
// Current target is not valid, try to reposition. // Current target is not valid, try to reposition.
Result<FindNearestPolyResult> fnp = navQuery.findNearestPoly(ag.targetPos, m_ext, Result<FindNearestPolyResult> fnp = navQuery.findNearestPoly(ag.targetPos, m_ext,
m_filters[ag.option.queryFilterType]); m_filters[ag.option.queryFilterType]);
ag.targetRef = fnp.succeeded() ? fnp.result.getNearestRef() : 0L; ag.targetRef = fnp.Succeeded() ? fnp.result.getNearestRef() : 0L;
if (fnp.succeeded()) if (fnp.Succeeded())
{ {
ag.targetPos = fnp.result.getNearestPos(); ag.targetPos = fnp.result.getNearestPos();
} }
@ -607,7 +607,7 @@ namespace DotRecast.Detour.Crowd
List<long> reqPath = pathFound.result; List<long> reqPath = pathFound.result;
Vector3f reqPos = new Vector3f(); Vector3f reqPos = new Vector3f();
if (pathFound.succeeded() && reqPath.Count > 0) if (pathFound.Succeeded() && reqPath.Count > 0)
{ {
// In progress or succeed. // In progress or succeed.
if (reqPath[reqPath.Count - 1] != ag.targetRef) if (reqPath[reqPath.Count - 1] != ag.targetRef)
@ -616,7 +616,7 @@ namespace DotRecast.Detour.Crowd
// last polygon. // last polygon.
Result<ClosestPointOnPolyResult> cr = navQuery.closestPointOnPoly(reqPath[reqPath.Count - 1], Result<ClosestPointOnPolyResult> cr = navQuery.closestPointOnPoly(reqPath[reqPath.Count - 1],
ag.targetPos); ag.targetPos);
if (cr.succeeded()) if (cr.Succeeded())
{ {
reqPos = cr.result.getClosest(); reqPos = cr.result.getClosest();
} }
@ -784,7 +784,7 @@ namespace DotRecast.Detour.Crowd
// Partial path, constrain target position inside // Partial path, constrain target position inside
// the last polygon. // the last polygon.
Result<ClosestPointOnPolyResult> cr = navQuery.closestPointOnPoly(res[res.Count - 1], targetPos); Result<ClosestPointOnPolyResult> cr = navQuery.closestPointOnPoly(res[res.Count - 1], targetPos);
if (cr.succeeded()) if (cr.Succeeded())
{ {
targetPos = cr.result.getClosest(); targetPos = cr.result.getClosest();
} }

View File

@ -110,7 +110,7 @@ namespace DotRecast.Detour.Crowd
// First query non-overlapping polygons. // First query non-overlapping polygons.
Result<FindLocalNeighbourhoodResult> res = navquery.findLocalNeighbourhood(refs, pos, collisionQueryRange, Result<FindLocalNeighbourhoodResult> res = navquery.findLocalNeighbourhood(refs, pos, collisionQueryRange,
filter); filter);
if (res.succeeded()) if (res.Succeeded())
{ {
m_polys = res.result.getRefs(); m_polys = res.result.getRefs();
m_segs.Clear(); m_segs.Clear();
@ -118,7 +118,7 @@ namespace DotRecast.Detour.Crowd
for (int j = 0; j < m_polys.Count; ++j) for (int j = 0; j < m_polys.Count; ++j)
{ {
Result<GetPolyWallSegmentsResult> result = navquery.getPolyWallSegments(m_polys[j], false, filter); Result<GetPolyWallSegmentsResult> result = navquery.getPolyWallSegments(m_polys[j], false, filter);
if (result.succeeded()) if (result.Succeeded())
{ {
GetPolyWallSegmentsResult gpws = result.result; GetPolyWallSegmentsResult gpws = result.result;
for (int k = 0; k < gpws.countSegmentRefs(); ++k) for (int k = 0; k < gpws.countSegmentRefs(); ++k)

View File

@ -238,7 +238,7 @@ namespace DotRecast.Detour.Crowd
{ {
List<StraightPathItem> path = new List<StraightPathItem>(); List<StraightPathItem> path = new List<StraightPathItem>();
Result<List<StraightPathItem>> result = navquery.findStraightPath(m_pos, m_target, m_path, maxCorners, 0); Result<List<StraightPathItem>> result = navquery.findStraightPath(m_pos, m_target, m_path, maxCorners, 0);
if (result.succeeded()) if (result.Succeeded())
{ {
path = result.result; path = result.result;
// Prune points in the beginning of the path which are too close. // Prune points in the beginning of the path which are too close.
@ -319,7 +319,7 @@ namespace DotRecast.Detour.Crowd
Vector3f goal = vMad(m_pos, delta, pathOptimizationRange / dist); Vector3f goal = vMad(m_pos, delta, pathOptimizationRange / dist);
Result<RaycastHit> rc = navquery.raycast(m_path[0], m_pos, goal, filter, 0, 0); Result<RaycastHit> rc = navquery.raycast(m_path[0], m_pos, goal, filter, 0, 0);
if (rc.succeeded()) if (rc.Succeeded())
{ {
if (rc.result.path.Count > 1 && rc.result.t > 0.99f) if (rc.result.path.Count > 1 && rc.result.t > 0.99f)
{ {
@ -355,7 +355,7 @@ namespace DotRecast.Detour.Crowd
navquery.updateSlicedFindPath(maxIterations); navquery.updateSlicedFindPath(maxIterations);
Result<List<long>> fpr = navquery.finalizeSlicedFindPathPartial(m_path); Result<List<long>> fpr = navquery.finalizeSlicedFindPathPartial(m_path);
if (fpr.succeeded() && fpr.result.Count > 0) if (fpr.Succeeded() && fpr.result.Count > 0)
{ {
m_path = mergeCorridorStartShortcut(m_path, fpr.result); m_path = mergeCorridorStartShortcut(m_path, fpr.result);
return true; return true;
@ -389,7 +389,7 @@ namespace DotRecast.Detour.Crowd
NavMesh nav = navquery.getAttachedNavMesh(); NavMesh nav = navquery.getAttachedNavMesh();
var startEnd = nav.getOffMeshConnectionPolyEndPoints(refs[0], refs[1]); var startEnd = nav.getOffMeshConnectionPolyEndPoints(refs[0], refs[1]);
if (startEnd.succeeded()) if (startEnd.Succeeded())
{ {
m_pos = startEnd.result.Item2; m_pos = startEnd.result.Item2;
start = startEnd.result.Item1; start = startEnd.result.Item1;
@ -427,13 +427,13 @@ namespace DotRecast.Detour.Crowd
{ {
// Move along navmesh and update new position. // Move along navmesh and update new position.
Result<MoveAlongSurfaceResult> masResult = navquery.moveAlongSurface(m_path[0], m_pos, npos, filter); Result<MoveAlongSurfaceResult> masResult = navquery.moveAlongSurface(m_path[0], m_pos, npos, filter);
if (masResult.succeeded()) if (masResult.Succeeded())
{ {
m_path = mergeCorridorStartMoved(m_path, masResult.result.getVisited()); m_path = mergeCorridorStartMoved(m_path, masResult.result.getVisited());
// Adjust the position to stay on top of the navmesh. // Adjust the position to stay on top of the navmesh.
m_pos = masResult.result.getResultPos(); m_pos = masResult.result.getResultPos();
Result<float> hr = navquery.getPolyHeight(m_path[0], masResult.result.getResultPos()); Result<float> hr = navquery.getPolyHeight(m_path[0], masResult.result.getResultPos());
if (hr.succeeded()) if (hr.Succeeded())
{ {
m_pos[1] = hr.result; m_pos[1] = hr.result;
} }
@ -465,7 +465,7 @@ namespace DotRecast.Detour.Crowd
{ {
// Move along navmesh and update new position. // Move along navmesh and update new position.
Result<MoveAlongSurfaceResult> masResult = navquery.moveAlongSurface(m_path[m_path.Count - 1], m_target, npos, filter); Result<MoveAlongSurfaceResult> masResult = navquery.moveAlongSurface(m_path[m_path.Count - 1], m_target, npos, filter);
if (masResult.succeeded()) if (masResult.Succeeded())
{ {
m_path = mergeCorridorEndMoved(m_path, masResult.result.getVisited()); m_path = mergeCorridorEndMoved(m_path, masResult.result.getVisited());
// TODO: should we do that? // TODO: should we do that?
@ -540,7 +540,7 @@ namespace DotRecast.Detour.Crowd
// Clamp target pos to last poly // Clamp target pos to last poly
var result = navquery.closestPointOnPolyBoundary(m_path[m_path.Count - 1], m_target); var result = navquery.closestPointOnPolyBoundary(m_path[m_path.Count - 1], m_target);
if (result.succeeded()) if (result.Succeeded())
{ {
m_target = result.result; m_target = result.result;
} }

View File

@ -79,7 +79,7 @@ namespace DotRecast.Detour.Extras.Jumplink
navMeshQuery.queryPolygons(pt, halfExtents, filter, new PolyQueryInvoker((tile, poly, refs) => navMeshQuery.queryPolygons(pt, halfExtents, filter, new PolyQueryInvoker((tile, poly, refs) =>
{ {
Result<float> h = navMeshQuery.getPolyHeight(refs, pt); Result<float> h = navMeshQuery.getPolyHeight(refs, pt);
if (h.succeeded()) if (h.Succeeded())
{ {
float y = h.result; float y = h.result;
if (y > minHeight.Get() && y < maxHeight) if (y > minHeight.Get() && y < maxHeight)

View File

@ -45,14 +45,14 @@ namespace DotRecast.Detour
// Validate input // Validate input
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter) if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter)
{ {
return Results.invalidParam<List<long>>(); return Results.InvalidParam<List<long>>();
} }
if (startRef == endRef) if (startRef == endRef)
{ {
List<long> singlePath = new List<long>(1); List<long> singlePath = new List<long>(1);
singlePath.Add(startRef); singlePath.Add(startRef);
return Results.success(singlePath); return Results.Success(singlePath);
} }
m_nodePool.clear(); m_nodePool.clear();
@ -145,7 +145,7 @@ namespace DotRecast.Detour
{ {
var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (!midpod.failed()) if (!midpod.Failed())
{ {
neighbourNode.pos = midpod.result; neighbourNode.pos = midpod.result;
} }
@ -225,7 +225,7 @@ namespace DotRecast.Detour
status = Status.PARTIAL_RESULT; status = Status.PARTIAL_RESULT;
} }
return Results.of(status, path); return Results.Of(status, path);
} }
/** /**
@ -239,14 +239,14 @@ namespace DotRecast.Detour
{ {
if (!m_query.status.isInProgress()) if (!m_query.status.isInProgress())
{ {
return Results.of(m_query.status, 0); return Results.Of(m_query.status, 0);
} }
// Make sure the request is still valid. // Make sure the request is still valid.
if (!m_nav.isValidPolyRef(m_query.startRef) || !m_nav.isValidPolyRef(m_query.endRef)) if (!m_nav.isValidPolyRef(m_query.startRef) || !m_nav.isValidPolyRef(m_query.endRef))
{ {
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
return Results.of(m_query.status, 0); return Results.Of(m_query.status, 0);
} }
int iter = 0; int iter = 0;
@ -264,7 +264,7 @@ namespace DotRecast.Detour
{ {
m_query.lastBestNode = bestNode; m_query.lastBestNode = bestNode;
m_query.status = Status.SUCCSESS; m_query.status = Status.SUCCSESS;
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
// Get current poly and tile. // Get current poly and tile.
@ -272,11 +272,11 @@ namespace DotRecast.Detour
// data. // data.
long bestRef = bestNode.id; long bestRef = bestNode.id;
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(bestRef); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(bestRef);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
// The polygon has disappeared during the sliced query, fail. // The polygon has disappeared during the sliced query, fail.
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
MeshTile bestTile = tileAndPoly.result.Item1; MeshTile bestTile = tileAndPoly.result.Item1;
@ -300,13 +300,13 @@ namespace DotRecast.Detour
{ {
bool invalidParent = false; bool invalidParent = false;
tileAndPoly = m_nav.getTileAndPolyByRef(parentRef); tileAndPoly = m_nav.getTileAndPolyByRef(parentRef);
invalidParent = tileAndPoly.failed(); invalidParent = tileAndPoly.Failed();
if (invalidParent || (grandpaRef != 0 && !m_nav.isValidPolyRef(grandpaRef))) if (invalidParent || (grandpaRef != 0 && !m_nav.isValidPolyRef(grandpaRef)))
{ {
// The polygon has disappeared during the sliced query, // The polygon has disappeared during the sliced query,
// fail. // fail.
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
parentTile = tileAndPoly.result.Item1; parentTile = tileAndPoly.result.Item1;
@ -362,7 +362,7 @@ namespace DotRecast.Detour
{ {
var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midpod = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (!midpod.failed()) if (!midpod.Failed())
{ {
neighbourNode.pos = midpod.result; neighbourNode.pos = midpod.result;
} }
@ -378,7 +378,7 @@ namespace DotRecast.Detour
{ {
Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourNode.pos, m_query.filter, Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourNode.pos, m_query.filter,
DT_RAYCAST_USE_COSTS, grandpaRef); DT_RAYCAST_USE_COSTS, grandpaRef);
if (rayHit.succeeded()) if (rayHit.Succeeded())
{ {
foundShortCut = rayHit.result.t >= 1.0f; foundShortCut = rayHit.result.t >= 1.0f;
if (foundShortCut) if (foundShortCut)
@ -467,7 +467,7 @@ namespace DotRecast.Detour
m_query.status = Status.PARTIAL_RESULT; m_query.status = Status.PARTIAL_RESULT;
} }
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
/// Finalizes and returns the results of a sliced path query. /// Finalizes and returns the results of a sliced path query.
@ -481,7 +481,7 @@ namespace DotRecast.Detour
{ {
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.failure(path); return Results.Failure(path);
} }
if (m_query.startRef == m_query.endRef) if (m_query.startRef == m_query.endRef)
@ -521,7 +521,7 @@ namespace DotRecast.Detour
if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0) if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0)
{ {
Result<RaycastHit> iresult = raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0); Result<RaycastHit> iresult = raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0);
if (iresult.succeeded()) if (iresult.Succeeded())
{ {
path.AddRange(iresult.result.path); path.AddRange(iresult.result.path);
} }
@ -545,7 +545,7 @@ namespace DotRecast.Detour
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.of(status, path); return Results.Of(status, path);
} }
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest /// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
@ -560,14 +560,14 @@ namespace DotRecast.Detour
List<long> path = new List<long>(64); List<long> path = new List<long>(64);
if (null == existing || existing.Count <= 0) if (null == existing || existing.Count <= 0)
{ {
return Results.failure(path); return Results.Failure(path);
} }
if (m_query.status.isFailed()) if (m_query.status.isFailed())
{ {
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.failure(path); return Results.Failure(path);
} }
if (m_query.startRef == m_query.endRef) if (m_query.startRef == m_query.endRef)
@ -618,7 +618,7 @@ namespace DotRecast.Detour
if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0) if ((node.flags & Node.DT_NODE_PARENT_DETACHED) != 0)
{ {
Result<RaycastHit> iresult = raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0); Result<RaycastHit> iresult = raycast(node.id, node.pos, next.pos, m_query.filter, 0, 0);
if (iresult.succeeded()) if (iresult.Succeeded())
{ {
path.AddRange(iresult.result.path); path.AddRange(iresult.result.path);
} }
@ -642,7 +642,7 @@ namespace DotRecast.Detour
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.of(status, path); return Results.Of(status, path);
} }
public override Result<FindDistanceToWallResult> findDistanceToWall(long startRef, Vector3f centerPos, float maxRadius, QueryFilter filter) public override Result<FindDistanceToWallResult> findDistanceToWall(long startRef, Vector3f centerPos, float maxRadius, QueryFilter filter)
@ -651,7 +651,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0 if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0
|| !float.IsFinite(maxRadius) || null == filter) || !float.IsFinite(maxRadius) || null == filter)
{ {
return Results.invalidParam<FindDistanceToWallResult>(); return Results.InvalidParam<FindDistanceToWallResult>();
} }
m_nodePool.clear(); m_nodePool.clear();
@ -808,7 +808,7 @@ namespace DotRecast.Detour
{ {
var midPoint = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midPoint = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (midPoint.succeeded()) if (midPoint.Succeeded())
{ {
neighbourNode.pos = midPoint.result; neighbourNode.pos = midPoint.result;
} }
@ -850,7 +850,7 @@ namespace DotRecast.Detour
vNormalize(ref hitNormal); vNormalize(ref hitNormal);
} }
return Results.success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal)); return Results.Success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal));
} }
} }
} }

View File

@ -225,7 +225,7 @@ namespace DotRecast.Detour
{ {
if (refs == 0) if (refs == 0)
{ {
return Results.invalidParam<Tuple<MeshTile, Poly>>("ref = 0"); return Results.InvalidParam<Tuple<MeshTile, Poly>>("ref = 0");
} }
int[] saltitip = decodePolyId(refs); int[] saltitip = decodePolyId(refs);
@ -234,20 +234,20 @@ namespace DotRecast.Detour
int ip = saltitip[2]; int ip = saltitip[2];
if (it >= m_maxTiles) if (it >= m_maxTiles)
{ {
return Results.invalidParam<Tuple<MeshTile, Poly>>("tile > m_maxTiles"); return Results.InvalidParam<Tuple<MeshTile, Poly>>("tile > m_maxTiles");
} }
if (m_tiles[it].salt != salt || m_tiles[it].data.header == null) if (m_tiles[it].salt != salt || m_tiles[it].data.header == null)
{ {
return Results.invalidParam<Tuple<MeshTile, Poly>>("Invalid salt or header"); return Results.InvalidParam<Tuple<MeshTile, Poly>>("Invalid salt or header");
} }
if (ip >= m_tiles[it].data.header.polyCount) if (ip >= m_tiles[it].data.header.polyCount)
{ {
return Results.invalidParam<Tuple<MeshTile, Poly>>("poly > polyCount"); return Results.InvalidParam<Tuple<MeshTile, Poly>>("poly > polyCount");
} }
return Results.success(Tuple.Create(m_tiles[it], m_tiles[it].data.polys[ip])); return Results.Success(Tuple.Create(m_tiles[it], m_tiles[it].data.polys[ip]));
} }
/// @par /// @par
@ -1523,7 +1523,7 @@ namespace DotRecast.Detour
{ {
if (polyRef == 0) if (polyRef == 0)
{ {
return Results.invalidParam<Tuple<Vector3f, Vector3f>>("polyRef = 0"); return Results.InvalidParam<Tuple<Vector3f, Vector3f>>("polyRef = 0");
} }
// Get current polygon // Get current polygon
@ -1533,18 +1533,18 @@ namespace DotRecast.Detour
int ip = saltitip[2]; int ip = saltitip[2];
if (it >= m_maxTiles) if (it >= m_maxTiles)
{ {
return Results.invalidParam<Tuple<Vector3f, Vector3f>>("Invalid tile ID > max tiles"); return Results.InvalidParam<Tuple<Vector3f, Vector3f>>("Invalid tile ID > max tiles");
} }
if (m_tiles[it].salt != salt || m_tiles[it].data.header == null) if (m_tiles[it].salt != salt || m_tiles[it].data.header == null)
{ {
return Results.invalidParam<Tuple<Vector3f, Vector3f>>("Invalid salt or missing tile header"); return Results.InvalidParam<Tuple<Vector3f, Vector3f>>("Invalid salt or missing tile header");
} }
MeshTile tile = m_tiles[it]; MeshTile tile = m_tiles[it];
if (ip >= tile.data.header.polyCount) if (ip >= tile.data.header.polyCount)
{ {
return Results.invalidParam<Tuple<Vector3f, Vector3f>>("Invalid poly ID > poly count"); return Results.InvalidParam<Tuple<Vector3f, Vector3f>>("Invalid poly ID > poly count");
} }
Poly poly = tile.data.polys[ip]; Poly poly = tile.data.polys[ip];
@ -1552,7 +1552,7 @@ namespace DotRecast.Detour
// Make sure that the current poly is indeed off-mesh link. // Make sure that the current poly is indeed off-mesh link.
if (poly.getType() != Poly.DT_POLYTYPE_OFFMESH_CONNECTION) if (poly.getType() != Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
{ {
return Results.invalidParam<Tuple<Vector3f, Vector3f>>("Invalid poly type"); return Results.InvalidParam<Tuple<Vector3f, Vector3f>>("Invalid poly type");
} }
// Figure out which way to hand out the vertices. // Figure out which way to hand out the vertices.
@ -1577,7 +1577,7 @@ namespace DotRecast.Detour
Vector3f endPos = new Vector3f(); Vector3f endPos = new Vector3f();
vCopy(ref startPos, tile.data.verts, poly.verts[idx0] * 3); vCopy(ref startPos, tile.data.verts, poly.verts[idx0] * 3);
vCopy(ref endPos, tile.data.verts, poly.verts[idx1] * 3); vCopy(ref endPos, tile.data.verts, poly.verts[idx1] * 3);
return Results.success(Tuple.Create(startPos, endPos)); return Results.Success(Tuple.Create(startPos, endPos));
} }
public int getMaxVertsPerPoly() public int getMaxVertsPerPoly()
@ -1628,7 +1628,7 @@ namespace DotRecast.Detour
{ {
if (refs == 0) if (refs == 0)
{ {
return Results.failure<int>(); return Results.Failure<int>();
} }
int[] saltTilePoly = decodePolyId(refs); int[] saltTilePoly = decodePolyId(refs);
@ -1637,23 +1637,23 @@ namespace DotRecast.Detour
int ip = saltTilePoly[2]; int ip = saltTilePoly[2];
if (it >= m_maxTiles) if (it >= m_maxTiles)
{ {
return Results.invalidParam<int>(); return Results.InvalidParam<int>();
} }
if (m_tiles[it].salt != salt || m_tiles[it].data == null || m_tiles[it].data.header == null) if (m_tiles[it].salt != salt || m_tiles[it].data == null || m_tiles[it].data.header == null)
{ {
return Results.invalidParam<int>(); return Results.InvalidParam<int>();
} }
MeshTile tile = m_tiles[it]; MeshTile tile = m_tiles[it];
if (ip >= tile.data.header.polyCount) if (ip >= tile.data.header.polyCount)
{ {
return Results.invalidParam<int>(); return Results.InvalidParam<int>();
} }
Poly poly = tile.data.polys[ip]; Poly poly = tile.data.polys[ip];
return Results.success(poly.flags); return Results.Success(poly.flags);
} }
public Status setPolyArea(long refs, char area) public Status setPolyArea(long refs, char area)
@ -1694,7 +1694,7 @@ namespace DotRecast.Detour
{ {
if (refs == 0) if (refs == 0)
{ {
return Results.failure<int>(); return Results.Failure<int>();
} }
int[] saltTilePoly = decodePolyId(refs); int[] saltTilePoly = decodePolyId(refs);
@ -1703,23 +1703,23 @@ namespace DotRecast.Detour
int ip = saltTilePoly[2]; int ip = saltTilePoly[2];
if (it >= m_maxTiles) if (it >= m_maxTiles)
{ {
return Results.invalidParam<int>(); return Results.InvalidParam<int>();
} }
if (m_tiles[it].salt != salt || m_tiles[it].data == null || m_tiles[it].data.header == null) if (m_tiles[it].salt != salt || m_tiles[it].data == null || m_tiles[it].data.header == null)
{ {
return Results.invalidParam<int>(); return Results.InvalidParam<int>();
} }
MeshTile tile = m_tiles[it]; MeshTile tile = m_tiles[it];
if (ip >= tile.data.header.polyCount) if (ip >= tile.data.header.polyCount)
{ {
return Results.invalidParam<int>(); return Results.InvalidParam<int>();
} }
Poly poly = tile.data.polys[ip]; Poly poly = tile.data.polys[ip];
return Results.success(poly.getArea()); return Results.Success(poly.getArea());
} }
/** /**

View File

@ -88,7 +88,7 @@ namespace DotRecast.Detour
// Randomly pick one tile. Assume that all tiles cover roughly the same area. // Randomly pick one tile. Assume that all tiles cover roughly the same area.
if (null == filter || null == frand) if (null == filter || null == frand)
{ {
return Results.invalidParam<FindRandomPointResult>(); return Results.InvalidParam<FindRandomPointResult>();
} }
MeshTile tile = null; MeshTile tile = null;
@ -113,7 +113,7 @@ namespace DotRecast.Detour
if (tile == null) if (tile == null)
{ {
return Results.invalidParam<FindRandomPointResult>("Tile not found"); return Results.InvalidParam<FindRandomPointResult>("Tile not found");
} }
// Randomly pick one polygon weighted by polygon area. // Randomly pick one polygon weighted by polygon area.
@ -160,7 +160,7 @@ namespace DotRecast.Detour
if (poly == null) if (poly == null)
{ {
return Results.invalidParam<FindRandomPointResult>("Poly not found"); return Results.InvalidParam<FindRandomPointResult>("Poly not found");
} }
// Randomly pick point on polygon. // Randomly pick point on polygon.
@ -177,7 +177,7 @@ namespace DotRecast.Detour
var pt = randomPointInConvexPoly(verts, poly.vertCount, areas, s, t); var pt = randomPointInConvexPoly(verts, poly.vertCount, areas, s, t);
ClosestPointOnPolyResult closest = closestPointOnPoly(polyRef, pt).result; ClosestPointOnPolyResult closest = closestPointOnPoly(polyRef, pt).result;
return Results.success(new FindRandomPointResult(polyRef, closest.getClosest())); return Results.Success(new FindRandomPointResult(polyRef, closest.getClosest()));
} }
/** /**
@ -230,7 +230,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0 if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0
|| !float.IsFinite(maxRadius) || null == filter || null == frand) || !float.IsFinite(maxRadius) || null == filter || null == frand)
{ {
return Results.invalidParam<FindRandomPointResult>(); return Results.InvalidParam<FindRandomPointResult>();
} }
Tuple<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(startRef); Tuple<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(startRef);
@ -238,7 +238,7 @@ namespace DotRecast.Detour
Poly startPoly = tileAndPoly.Item2; Poly startPoly = tileAndPoly.Item2;
if (!filter.passFilter(startRef, startTile, startPoly)) if (!filter.passFilter(startRef, startTile, startPoly))
{ {
return Results.invalidParam<FindRandomPointResult>("Invalid start ref"); return Results.InvalidParam<FindRandomPointResult>("Invalid start ref");
} }
m_nodePool.clear(); m_nodePool.clear();
@ -338,7 +338,7 @@ namespace DotRecast.Detour
// Find edge and calc distance to the edge. // Find edge and calc distance to the edge.
Result<PortalResult> portalpoints = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, Result<PortalResult> portalpoints = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef,
neighbourPoly, neighbourTile, 0, 0); neighbourPoly, neighbourTile, 0, 0);
if (portalpoints.failed()) if (portalpoints.Failed())
{ {
continue; continue;
} }
@ -394,7 +394,7 @@ namespace DotRecast.Detour
if (randomPoly == null) if (randomPoly == null)
{ {
return Results.failure<FindRandomPointResult>(); return Results.Failure<FindRandomPointResult>();
} }
// Randomly pick point on polygon. // Randomly pick point on polygon.
@ -404,7 +404,7 @@ namespace DotRecast.Detour
float[] areas = new float[randomPolyVerts.Length / 3]; float[] areas = new float[randomPolyVerts.Length / 3];
Vector3f pt = randomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas, s, t); Vector3f pt = randomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas, s, t);
ClosestPointOnPolyResult closest = closestPointOnPoly(randomPolyRef, pt).result; ClosestPointOnPolyResult closest = closestPointOnPoly(randomPolyRef, pt).result;
return Results.success(new FindRandomPointResult(randomPolyRef, closest.getClosest())); return Results.Success(new FindRandomPointResult(randomPolyRef, closest.getClosest()));
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -426,10 +426,10 @@ namespace DotRecast.Detour
{ {
if (!m_nav.isValidPolyRef(refs) || !vIsFinite(pos)) if (!m_nav.isValidPolyRef(refs) || !vIsFinite(pos))
{ {
return Results.invalidParam<ClosestPointOnPolyResult>(); return Results.InvalidParam<ClosestPointOnPolyResult>();
} }
return Results.success(m_nav.closestPointOnPoly(refs, pos)); return Results.Success(m_nav.closestPointOnPoly(refs, pos));
} }
/// @par /// @par
@ -452,21 +452,21 @@ namespace DotRecast.Detour
public Result<Vector3f> closestPointOnPolyBoundary(long refs, Vector3f pos) public Result<Vector3f> closestPointOnPolyBoundary(long refs, Vector3f pos)
{ {
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(refs); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(refs);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
return Results.of<Vector3f>(tileAndPoly.status, tileAndPoly.message); return Results.Of<Vector3f>(tileAndPoly.status, tileAndPoly.message);
} }
MeshTile tile = tileAndPoly.result.Item1; MeshTile tile = tileAndPoly.result.Item1;
Poly poly = tileAndPoly.result.Item2; Poly poly = tileAndPoly.result.Item2;
if (tile == null) if (tile == null)
{ {
return Results.invalidParam<Vector3f>("Invalid tile"); return Results.InvalidParam<Vector3f>("Invalid tile");
} }
if (!vIsFinite(pos)) if (!vIsFinite(pos))
{ {
return Results.invalidParam<Vector3f>(); return Results.InvalidParam<Vector3f>();
} }
// Collect vertices. // Collect vertices.
@ -503,7 +503,7 @@ namespace DotRecast.Detour
closest = vLerp(verts, va, vb, edget[imin]); closest = vLerp(verts, va, vb, edget[imin]);
} }
return Results.success(closest); return Results.Success(closest);
} }
/// @par /// @par
@ -519,9 +519,9 @@ namespace DotRecast.Detour
public Result<float> getPolyHeight(long refs, Vector3f pos) public Result<float> getPolyHeight(long refs, Vector3f pos)
{ {
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(refs); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(refs);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
return Results.of<float>(tileAndPoly.status, tileAndPoly.message); return Results.Of<float>(tileAndPoly.status, tileAndPoly.message);
} }
MeshTile tile = tileAndPoly.result.Item1; MeshTile tile = tileAndPoly.result.Item1;
@ -529,7 +529,7 @@ namespace DotRecast.Detour
if (!vIsFinite2D(pos)) if (!vIsFinite2D(pos))
{ {
return Results.invalidParam<float>(); return Results.InvalidParam<float>();
} }
// We used to return success for offmesh connections, but the // We used to return success for offmesh connections, but the
@ -542,11 +542,11 @@ namespace DotRecast.Detour
i = poly.verts[1] * 3; i = poly.verts[1] * 3;
var v1 = new Vector3f { x = tile.data.verts[i], y = tile.data.verts[i + 1], z = tile.data.verts[i + 2] }; var v1 = new Vector3f { x = tile.data.verts[i], y = tile.data.verts[i + 1], z = tile.data.verts[i + 2] };
var dt = distancePtSegSqr2D(pos, v0, v1); var dt = distancePtSegSqr2D(pos, v0, v1);
return Results.success(v0[1] + (v1[1] - v0[1]) * dt.Item2); return Results.Success(v0[1] + (v1[1] - v0[1]) * dt.Item2);
} }
float? height = m_nav.getPolyHeight(tile, poly, pos); float? height = m_nav.getPolyHeight(tile, poly, pos);
return null != height ? Results.success(height.Value) : Results.invalidParam<float>(); return null != height ? Results.Success(height.Value) : Results.InvalidParam<float>();
} }
/** /**
@ -568,10 +568,10 @@ namespace DotRecast.Detour
Status status = queryPolygons(center, halfExtents, filter, query); Status status = queryPolygons(center, halfExtents, filter, query);
if (status.isFailed()) if (status.isFailed())
{ {
return Results.of<FindNearestPolyResult>(status, ""); return Results.Of<FindNearestPolyResult>(status, "");
} }
return Results.success(query.result()); return Results.Success(query.result());
} }
// FIXME: (PP) duplicate? // FIXME: (PP) duplicate?
@ -767,7 +767,7 @@ namespace DotRecast.Detour
// Validate input // Validate input
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter) if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter)
{ {
return Results.invalidParam<List<long>>(); return Results.InvalidParam<List<long>>();
} }
float raycastLimitSqr = sqr(raycastLimit); float raycastLimitSqr = sqr(raycastLimit);
@ -786,7 +786,7 @@ namespace DotRecast.Detour
{ {
List<long> singlePath = new List<long>(1); List<long> singlePath = new List<long>(1);
singlePath.Add(startRef); singlePath.Add(startRef);
return Results.success(singlePath); return Results.Success(singlePath);
} }
m_nodePool.clear(); m_nodePool.clear();
@ -897,7 +897,7 @@ namespace DotRecast.Detour
? getEdgeIntersectionPoint(bestNode.pos, bestRef, bestPoly, bestTile, endPos, neighbourRef, ? getEdgeIntersectionPoint(bestNode.pos, bestRef, bestPoly, bestTile, endPos, neighbourRef,
neighbourPoly, neighbourTile) neighbourPoly, neighbourTile)
: getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile); : getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile);
if (!midpod.failed()) if (!midpod.Failed())
{ {
neighbourPos = midpod.result; neighbourPos = midpod.result;
} }
@ -913,7 +913,7 @@ namespace DotRecast.Detour
{ {
Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourPos, filter, Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourPos, filter,
DT_RAYCAST_USE_COSTS, grandpaRef); DT_RAYCAST_USE_COSTS, grandpaRef);
if (rayHit.succeeded()) if (rayHit.Succeeded())
{ {
foundShortCut = rayHit.result.t >= 1.0f; foundShortCut = rayHit.result.t >= 1.0f;
if (foundShortCut) if (foundShortCut)
@ -999,7 +999,7 @@ namespace DotRecast.Detour
status = Status.PARTIAL_RESULT; status = Status.PARTIAL_RESULT;
} }
return Results.of(status, path); return Results.Of(status, path);
} }
/** /**
@ -1101,14 +1101,14 @@ namespace DotRecast.Detour
{ {
if (!m_query.status.isInProgress()) if (!m_query.status.isInProgress())
{ {
return Results.of(m_query.status, 0); return Results.Of(m_query.status, 0);
} }
// Make sure the request is still valid. // Make sure the request is still valid.
if (!m_nav.isValidPolyRef(m_query.startRef) || !m_nav.isValidPolyRef(m_query.endRef)) if (!m_nav.isValidPolyRef(m_query.startRef) || !m_nav.isValidPolyRef(m_query.endRef))
{ {
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
return Results.of(m_query.status, 0); return Results.Of(m_query.status, 0);
} }
int iter = 0; int iter = 0;
@ -1126,7 +1126,7 @@ namespace DotRecast.Detour
{ {
m_query.lastBestNode = bestNode; m_query.lastBestNode = bestNode;
m_query.status = Status.SUCCSESS; m_query.status = Status.SUCCSESS;
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
// Get current poly and tile. // Get current poly and tile.
@ -1134,11 +1134,11 @@ namespace DotRecast.Detour
// data. // data.
long bestRef = bestNode.id; long bestRef = bestNode.id;
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(bestRef); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(bestRef);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
// The polygon has disappeared during the sliced query, fail. // The polygon has disappeared during the sliced query, fail.
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
MeshTile bestTile = tileAndPoly.result.Item1; MeshTile bestTile = tileAndPoly.result.Item1;
@ -1162,13 +1162,13 @@ namespace DotRecast.Detour
{ {
bool invalidParent = false; bool invalidParent = false;
tileAndPoly = m_nav.getTileAndPolyByRef(parentRef); tileAndPoly = m_nav.getTileAndPolyByRef(parentRef);
invalidParent = tileAndPoly.failed(); invalidParent = tileAndPoly.Failed();
if (invalidParent || (grandpaRef != 0 && !m_nav.isValidPolyRef(grandpaRef))) if (invalidParent || (grandpaRef != 0 && !m_nav.isValidPolyRef(grandpaRef)))
{ {
// The polygon has disappeared during the sliced query, // The polygon has disappeared during the sliced query,
// fail. // fail.
m_query.status = Status.FAILURE; m_query.status = Status.FAILURE;
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
parentTile = tileAndPoly.result.Item1; parentTile = tileAndPoly.result.Item1;
@ -1226,7 +1226,7 @@ namespace DotRecast.Detour
? getEdgeIntersectionPoint(bestNode.pos, bestRef, bestPoly, bestTile, m_query.endPos, ? getEdgeIntersectionPoint(bestNode.pos, bestRef, bestPoly, bestTile, m_query.endPos,
neighbourRef, neighbourPoly, neighbourTile) neighbourRef, neighbourPoly, neighbourTile)
: getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile); : getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile);
if (!midpod.failed()) if (!midpod.Failed())
{ {
neighbourPos = midpod.result; neighbourPos = midpod.result;
} }
@ -1242,7 +1242,7 @@ namespace DotRecast.Detour
{ {
Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourPos, m_query.filter, Result<RaycastHit> rayHit = raycast(parentRef, parentNode.pos, neighbourPos, m_query.filter,
DT_RAYCAST_USE_COSTS, grandpaRef); DT_RAYCAST_USE_COSTS, grandpaRef);
if (rayHit.succeeded()) if (rayHit.Succeeded())
{ {
foundShortCut = rayHit.result.t >= 1.0f; foundShortCut = rayHit.result.t >= 1.0f;
if (foundShortCut) if (foundShortCut)
@ -1330,7 +1330,7 @@ namespace DotRecast.Detour
m_query.status = Status.PARTIAL_RESULT; m_query.status = Status.PARTIAL_RESULT;
} }
return Results.of(m_query.status, iter); return Results.Of(m_query.status, iter);
} }
/// Finalizes and returns the results of a sliced path query. /// Finalizes and returns the results of a sliced path query.
@ -1344,7 +1344,7 @@ namespace DotRecast.Detour
{ {
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.failure(path); return Results.Failure(path);
} }
if (m_query.startRef == m_query.endRef) if (m_query.startRef == m_query.endRef)
@ -1367,7 +1367,7 @@ namespace DotRecast.Detour
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.of(status, path); return Results.Of(status, path);
} }
/// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest /// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest
@ -1382,14 +1382,14 @@ namespace DotRecast.Detour
List<long> path = new List<long>(64); List<long> path = new List<long>(64);
if (null == existing || existing.Count <= 0) if (null == existing || existing.Count <= 0)
{ {
return Results.failure(path); return Results.Failure(path);
} }
if (m_query.status.isFailed()) if (m_query.status.isFailed())
{ {
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.failure(path); return Results.Failure(path);
} }
if (m_query.startRef == m_query.endRef) if (m_query.startRef == m_query.endRef)
@ -1423,7 +1423,7 @@ namespace DotRecast.Detour
// Reset query. // Reset query.
m_query = new QueryData(); m_query = new QueryData();
return Results.of(status, path); return Results.Of(status, path);
} }
protected Status appendVertex(Vector3f pos, int flags, long refs, List<StraightPathItem> straightPath, protected Status appendVertex(Vector3f pos, int flags, long refs, List<StraightPathItem> straightPath,
@ -1464,7 +1464,7 @@ namespace DotRecast.Detour
// Calculate portal // Calculate portal
long from = path[i]; long from = path[i];
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(from); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(from);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
return Status.FAILURE; return Status.FAILURE;
} }
@ -1474,7 +1474,7 @@ namespace DotRecast.Detour
long to = path[i + 1]; long to = path[i + 1];
tileAndPoly = m_nav.getTileAndPolyByRef(to); tileAndPoly = m_nav.getTileAndPolyByRef(to);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
return Status.FAILURE; return Status.FAILURE;
} }
@ -1483,7 +1483,7 @@ namespace DotRecast.Detour
Poly toPoly = tileAndPoly.result.Item2; Poly toPoly = tileAndPoly.result.Item2;
Result<PortalResult> portals = getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, 0, 0); Result<PortalResult> portals = getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, 0, 0);
if (portals.failed()) if (portals.Failed())
{ {
break; break;
} }
@ -1549,21 +1549,21 @@ namespace DotRecast.Detour
if (!vIsFinite(startPos) || !vIsFinite(endPos) if (!vIsFinite(startPos) || !vIsFinite(endPos)
|| null == path || 0 == path.Count || path[0] == 0 || maxStraightPath <= 0) || null == path || 0 == path.Count || path[0] == 0 || maxStraightPath <= 0)
{ {
return Results.invalidParam<List<StraightPathItem>>(); return Results.InvalidParam<List<StraightPathItem>>();
} }
// TODO: Should this be callers responsibility? // TODO: Should this be callers responsibility?
Result<Vector3f> closestStartPosRes = closestPointOnPolyBoundary(path[0], startPos); Result<Vector3f> closestStartPosRes = closestPointOnPolyBoundary(path[0], startPos);
if (closestStartPosRes.failed()) if (closestStartPosRes.Failed())
{ {
return Results.invalidParam<List<StraightPathItem>>("Cannot find start position"); return Results.InvalidParam<List<StraightPathItem>>("Cannot find start position");
} }
var closestStartPos = closestStartPosRes.result; var closestStartPos = closestStartPosRes.result;
var closestEndPosRes = closestPointOnPolyBoundary(path[path.Count - 1], endPos); var closestEndPosRes = closestPointOnPolyBoundary(path[path.Count - 1], endPos);
if (closestEndPosRes.failed()) if (closestEndPosRes.Failed())
{ {
return Results.invalidParam<List<StraightPathItem>>("Cannot find end position"); return Results.InvalidParam<List<StraightPathItem>>("Cannot find end position");
} }
var closestEndPos = closestEndPosRes.result; var closestEndPos = closestEndPosRes.result;
@ -1571,7 +1571,7 @@ namespace DotRecast.Detour
Status stat = appendVertex(closestStartPos, DT_STRAIGHTPATH_START, path[0], straightPath, maxStraightPath); Status stat = appendVertex(closestStartPos, DT_STRAIGHTPATH_START, path[0], straightPath, maxStraightPath);
if (!stat.isInProgress()) if (!stat.isInProgress())
{ {
return Results.success(straightPath); return Results.Success(straightPath);
} }
if (path.Count > 1) if (path.Count > 1)
@ -1599,12 +1599,12 @@ namespace DotRecast.Detour
{ {
// Next portal. // Next portal.
Result<PortalResult> portalPoints = getPortalPoints(path[i], path[i + 1]); Result<PortalResult> portalPoints = getPortalPoints(path[i], path[i + 1]);
if (portalPoints.failed()) if (portalPoints.Failed())
{ {
closestEndPosRes = closestPointOnPolyBoundary(path[i], endPos); closestEndPosRes = closestPointOnPolyBoundary(path[i], endPos);
if (closestEndPosRes.failed()) if (closestEndPosRes.Failed())
{ {
return Results.invalidParam<List<StraightPathItem>>(); return Results.InvalidParam<List<StraightPathItem>>();
} }
closestEndPos = closestEndPosRes.result; closestEndPos = closestEndPosRes.result;
@ -1617,7 +1617,7 @@ namespace DotRecast.Detour
// Ignore status return value as we're just about to return anyway. // Ignore status return value as we're just about to return anyway.
appendVertex(closestEndPos, 0, path[i], straightPath, maxStraightPath); appendVertex(closestEndPos, 0, path[i], straightPath, maxStraightPath);
return Results.success(straightPath); return Results.Success(straightPath);
} }
left = portalPoints.result.left; left = portalPoints.result.left;
@ -1661,7 +1661,7 @@ namespace DotRecast.Detour
options); options);
if (!stat.isInProgress()) if (!stat.isInProgress())
{ {
return Results.success(straightPath); return Results.Success(straightPath);
} }
} }
@ -1684,7 +1684,7 @@ namespace DotRecast.Detour
stat = appendVertex(portalApex, flags, refs, straightPath, maxStraightPath); stat = appendVertex(portalApex, flags, refs, straightPath, maxStraightPath);
if (!stat.isInProgress()) if (!stat.isInProgress())
{ {
return Results.success(straightPath); return Results.Success(straightPath);
} }
portalLeft = portalApex; portalLeft = portalApex;
@ -1718,7 +1718,7 @@ namespace DotRecast.Detour
maxStraightPath, options); maxStraightPath, options);
if (!stat.isInProgress()) if (!stat.isInProgress())
{ {
return Results.success(straightPath); return Results.Success(straightPath);
} }
} }
@ -1741,7 +1741,7 @@ namespace DotRecast.Detour
stat = appendVertex(portalApex, flags, refs, straightPath, maxStraightPath); stat = appendVertex(portalApex, flags, refs, straightPath, maxStraightPath);
if (!stat.isInProgress()) if (!stat.isInProgress())
{ {
return Results.success(straightPath); return Results.Success(straightPath);
} }
portalLeft = portalApex; portalLeft = portalApex;
@ -1764,14 +1764,14 @@ namespace DotRecast.Detour
options); options);
if (!stat.isInProgress()) if (!stat.isInProgress())
{ {
return Results.success(straightPath); return Results.Success(straightPath);
} }
} }
} }
// Ignore status return value as we're just about to return anyway. // Ignore status return value as we're just about to return anyway.
appendVertex(closestEndPos, DT_STRAIGHTPATH_END, 0, straightPath, maxStraightPath); appendVertex(closestEndPos, DT_STRAIGHTPATH_END, 0, straightPath, maxStraightPath);
return Results.success(straightPath); return Results.Success(straightPath);
} }
/// @par /// @par
@ -1806,7 +1806,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(startPos) if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(startPos)
|| !vIsFinite(endPos) || null == filter) || !vIsFinite(endPos) || null == filter)
{ {
return Results.invalidParam<MoveAlongSurfaceResult>(); return Results.InvalidParam<MoveAlongSurfaceResult>();
} }
NodePool tinyNodePool = new NodePool(); NodePool tinyNodePool = new NodePool();
@ -1972,7 +1972,7 @@ namespace DotRecast.Detour
} while (node != null); } while (node != null);
} }
return Results.success(new MoveAlongSurfaceResult(bestPos, visited)); return Results.Success(new MoveAlongSurfaceResult(bestPos, visited));
} }
public class PortalResult public class PortalResult
@ -1994,9 +1994,9 @@ namespace DotRecast.Detour
protected Result<PortalResult> getPortalPoints(long from, long to) protected Result<PortalResult> getPortalPoints(long from, long to)
{ {
Result<Tuple<MeshTile, Poly>> tileAndPolyResult = m_nav.getTileAndPolyByRef(from); Result<Tuple<MeshTile, Poly>> tileAndPolyResult = m_nav.getTileAndPolyByRef(from);
if (tileAndPolyResult.failed()) if (tileAndPolyResult.Failed())
{ {
return Results.of<PortalResult>(tileAndPolyResult.status, tileAndPolyResult.message); return Results.Of<PortalResult>(tileAndPolyResult.status, tileAndPolyResult.message);
} }
Tuple<MeshTile, Poly> tileAndPoly = tileAndPolyResult.result; Tuple<MeshTile, Poly> tileAndPoly = tileAndPolyResult.result;
@ -2005,9 +2005,9 @@ namespace DotRecast.Detour
int fromType = fromPoly.getType(); int fromType = fromPoly.getType();
tileAndPolyResult = m_nav.getTileAndPolyByRef(to); tileAndPolyResult = m_nav.getTileAndPolyByRef(to);
if (tileAndPolyResult.failed()) if (tileAndPolyResult.Failed())
{ {
return Results.of<PortalResult>(tileAndPolyResult.status, tileAndPolyResult.message); return Results.Of<PortalResult>(tileAndPolyResult.status, tileAndPolyResult.message);
} }
tileAndPoly = tileAndPolyResult.result; tileAndPoly = tileAndPolyResult.result;
@ -2037,7 +2037,7 @@ namespace DotRecast.Detour
if (link == null) if (link == null)
{ {
return Results.invalidParam<PortalResult>("No link found"); return Results.InvalidParam<PortalResult>("No link found");
} }
// Handle off-mesh connections. // Handle off-mesh connections.
@ -2056,11 +2056,11 @@ namespace DotRecast.Detour
right[0] = fromTile.data.verts[fromPoly.verts[v] * 3]; right[0] = fromTile.data.verts[fromPoly.verts[v] * 3];
right[1] = fromTile.data.verts[fromPoly.verts[v] * 3 + 1]; right[1] = fromTile.data.verts[fromPoly.verts[v] * 3 + 1];
right[2] = fromTile.data.verts[fromPoly.verts[v] * 3 + 2]; right[2] = fromTile.data.verts[fromPoly.verts[v] * 3 + 2];
return Results.success(new PortalResult(left, right, fromType, toType)); return Results.Success(new PortalResult(left, right, fromType, toType));
} }
} }
return Results.invalidParam<PortalResult>("Invalid offmesh from connection"); return Results.InvalidParam<PortalResult>("Invalid offmesh from connection");
} }
if (toPoly.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION) if (toPoly.getType() == Poly.DT_POLYTYPE_OFFMESH_CONNECTION)
@ -2078,11 +2078,11 @@ namespace DotRecast.Detour
right[1] = toTile.data.verts[toPoly.verts[v] * 3 + 1]; right[1] = toTile.data.verts[toPoly.verts[v] * 3 + 1];
right[2] = toTile.data.verts[toPoly.verts[v] * 3 + 2]; right[2] = toTile.data.verts[toPoly.verts[v] * 3 + 2];
return Results.success(new PortalResult(left, right, fromType, toType)); return Results.Success(new PortalResult(left, right, fromType, toType));
} }
} }
return Results.invalidParam<PortalResult>("Invalid offmesh to connection"); return Results.InvalidParam<PortalResult>("Invalid offmesh to connection");
} }
// Find portal vertices. // Find portal vertices.
@ -2111,16 +2111,16 @@ namespace DotRecast.Detour
} }
} }
return Results.success(new PortalResult(left, right, fromType, toType)); return Results.Success(new PortalResult(left, right, fromType, toType));
} }
protected Result<Vector3f> getEdgeMidPoint(long from, Poly fromPoly, MeshTile fromTile, long to, protected Result<Vector3f> getEdgeMidPoint(long from, Poly fromPoly, MeshTile fromTile, long to,
Poly toPoly, MeshTile toTile) Poly toPoly, MeshTile toTile)
{ {
Result<PortalResult> ppoints = getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, 0, 0); Result<PortalResult> ppoints = getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, 0, 0);
if (ppoints.failed()) if (ppoints.Failed())
{ {
return Results.of<Vector3f>(ppoints.status, ppoints.message); return Results.Of<Vector3f>(ppoints.status, ppoints.message);
} }
var left = ppoints.result.left; var left = ppoints.result.left;
@ -2129,16 +2129,16 @@ namespace DotRecast.Detour
mid[0] = (left[0] + right[0]) * 0.5f; mid[0] = (left[0] + right[0]) * 0.5f;
mid[1] = (left[1] + right[1]) * 0.5f; mid[1] = (left[1] + right[1]) * 0.5f;
mid[2] = (left[2] + right[2]) * 0.5f; mid[2] = (left[2] + right[2]) * 0.5f;
return Results.success(mid); return Results.Success(mid);
} }
protected Result<Vector3f> getEdgeIntersectionPoint(Vector3f fromPos, long from, Poly fromPoly, MeshTile fromTile, protected Result<Vector3f> getEdgeIntersectionPoint(Vector3f fromPos, long from, Poly fromPoly, MeshTile fromTile,
Vector3f toPos, long to, Poly toPoly, MeshTile toTile) Vector3f toPos, long to, Poly toPoly, MeshTile toTile)
{ {
Result<PortalResult> ppoints = getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, 0, 0); Result<PortalResult> ppoints = getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, 0, 0);
if (ppoints.failed()) if (ppoints.Failed())
{ {
return Results.of<Vector3f>(ppoints.status, ppoints.message); return Results.Of<Vector3f>(ppoints.status, ppoints.message);
} }
Vector3f left = ppoints.result.left; Vector3f left = ppoints.result.left;
@ -2151,7 +2151,7 @@ namespace DotRecast.Detour
} }
Vector3f pt = vLerp(left, right, t); Vector3f pt = vLerp(left, right, t);
return Results.success(pt); return Results.Success(pt);
} }
private static float s = 1.0f / 255.0f; private static float s = 1.0f / 255.0f;
@ -2215,7 +2215,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(startPos) || !vIsFinite(endPos) || null == filter
|| (prevRef != 0 && !m_nav.isValidPolyRef(prevRef))) || (prevRef != 0 && !m_nav.isValidPolyRef(prevRef)))
{ {
return Results.invalidParam<RaycastHit>(); return Results.InvalidParam<RaycastHit>();
} }
RaycastHit hit = new RaycastHit(); RaycastHit hit = new RaycastHit();
@ -2261,7 +2261,7 @@ namespace DotRecast.Detour
if (!iresult.intersects) if (!iresult.intersects)
{ {
// Could not hit the polygon, keep the old t and report hit. // Could not hit the polygon, keep the old t and report hit.
return Results.success(hit); return Results.Success(hit);
} }
hit.hitEdgeIndex = iresult.segMax; hit.hitEdgeIndex = iresult.segMax;
@ -2287,7 +2287,7 @@ namespace DotRecast.Detour
curRef, tile, poly); curRef, tile, poly);
} }
return Results.success(hit); return Results.Success(hit);
} }
// Follow neighbours. // Follow neighbours.
@ -2417,7 +2417,7 @@ namespace DotRecast.Detour
hit.hitNormal[1] = 0; hit.hitNormal[1] = 0;
hit.hitNormal[2] = -dx; hit.hitNormal[2] = -dx;
vNormalize(ref hit.hitNormal); vNormalize(ref hit.hitNormal);
return Results.success(hit); return Results.Success(hit);
} }
// No hit, advance to neighbour polygon. // No hit, advance to neighbour polygon.
@ -2429,7 +2429,7 @@ namespace DotRecast.Detour
poly = nextPoly; poly = nextPoly;
} }
return Results.success(hit); return Results.Success(hit);
} }
/// @par /// @par
@ -2483,7 +2483,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || radius < 0 if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || radius < 0
|| !float.IsFinite(radius) || null == filter) || !float.IsFinite(radius) || null == filter)
{ {
return Results.invalidParam<FindPolysAroundResult>(); return Results.InvalidParam<FindPolysAroundResult>();
} }
List<long> resultRef = new List<long>(); List<long> resultRef = new List<long>();
@ -2561,7 +2561,7 @@ namespace DotRecast.Detour
// Find edge and calc distance to the edge. // Find edge and calc distance to the edge.
Result<PortalResult> pp = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, Result<PortalResult> pp = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile, 0, 0); neighbourTile, 0, 0);
if (pp.failed()) if (pp.Failed())
{ {
continue; continue;
} }
@ -2616,7 +2616,7 @@ namespace DotRecast.Detour
} }
} }
return Results.success(new FindPolysAroundResult(resultRef, resultParent, resultCost)); return Results.Success(new FindPolysAroundResult(resultRef, resultParent, resultCost));
} }
/// @par /// @par
@ -2660,7 +2660,7 @@ namespace DotRecast.Detour
int nverts = verts.Length / 3; int nverts = verts.Length / 3;
if (!m_nav.isValidPolyRef(startRef) || null == verts || nverts < 3 || null == filter) if (!m_nav.isValidPolyRef(startRef) || null == verts || nverts < 3 || null == filter)
{ {
return Results.invalidParam<FindPolysAroundResult>(); return Results.InvalidParam<FindPolysAroundResult>();
} }
List<long> resultRef = new List<long>(); List<long> resultRef = new List<long>();
@ -2749,7 +2749,7 @@ namespace DotRecast.Detour
// Find edge and calc distance to the edge. // Find edge and calc distance to the edge.
Result<PortalResult> pp = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, Result<PortalResult> pp = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile, 0, 0); neighbourTile, 0, 0);
if (pp.failed()) if (pp.Failed())
{ {
continue; continue;
} }
@ -2809,7 +2809,7 @@ namespace DotRecast.Detour
} }
} }
return Results.success(new FindPolysAroundResult(resultRef, resultParent, resultCost)); return Results.Success(new FindPolysAroundResult(resultRef, resultParent, resultCost));
} }
/// @par /// @par
@ -2852,7 +2852,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || radius < 0 if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || radius < 0
|| !float.IsFinite(radius) || null == filter) || !float.IsFinite(radius) || null == filter)
{ {
return Results.invalidParam<FindLocalNeighbourhoodResult>(); return Results.InvalidParam<FindLocalNeighbourhoodResult>();
} }
List<long> resultRef = new List<long>(); List<long> resultRef = new List<long>();
@ -2925,7 +2925,7 @@ namespace DotRecast.Detour
// Find edge and calc distance to the edge. // Find edge and calc distance to the edge.
Result<PortalResult> pp = getPortalPoints(curRef, curPoly, curTile, neighbourRef, neighbourPoly, Result<PortalResult> pp = getPortalPoints(curRef, curPoly, curTile, neighbourRef, neighbourPoly,
neighbourTile, 0, 0); neighbourTile, 0, 0);
if (pp.failed()) if (pp.Failed())
{ {
continue; continue;
} }
@ -3006,7 +3006,7 @@ namespace DotRecast.Detour
} }
} }
return Results.success(new FindLocalNeighbourhoodResult(resultRef, resultParent)); return Results.Success(new FindLocalNeighbourhoodResult(resultRef, resultParent));
} }
public class SegInterval public class SegInterval
@ -3063,14 +3063,14 @@ namespace DotRecast.Detour
public Result<GetPolyWallSegmentsResult> getPolyWallSegments(long refs, bool storePortals, QueryFilter filter) public Result<GetPolyWallSegmentsResult> getPolyWallSegments(long refs, bool storePortals, QueryFilter filter)
{ {
Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(refs); Result<Tuple<MeshTile, Poly>> tileAndPoly = m_nav.getTileAndPolyByRef(refs);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
return Results.of<GetPolyWallSegmentsResult>(tileAndPoly.status, tileAndPoly.message); return Results.Of<GetPolyWallSegmentsResult>(tileAndPoly.status, tileAndPoly.message);
} }
if (null == filter) if (null == filter)
{ {
return Results.invalidParam<GetPolyWallSegmentsResult>(); return Results.InvalidParam<GetPolyWallSegmentsResult>();
} }
MeshTile tile = tileAndPoly.result.Item1; MeshTile tile = tileAndPoly.result.Item1;
@ -3174,7 +3174,7 @@ namespace DotRecast.Detour
} }
} }
return Results.success(new GetPolyWallSegmentsResult(segmentVerts, segmentRefs)); return Results.Success(new GetPolyWallSegmentsResult(segmentVerts, segmentRefs));
} }
/// @par /// @par
@ -3204,7 +3204,7 @@ namespace DotRecast.Detour
if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0 if (!m_nav.isValidPolyRef(startRef) || !vIsFinite(centerPos) || maxRadius < 0
|| !float.IsFinite(maxRadius) || null == filter) || !float.IsFinite(maxRadius) || null == filter)
{ {
return Results.invalidParam<FindDistanceToWallResult>(); return Results.InvalidParam<FindDistanceToWallResult>();
} }
m_nodePool.clear(); m_nodePool.clear();
@ -3361,7 +3361,7 @@ namespace DotRecast.Detour
{ {
var midPoint = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, var midPoint = getEdgeMidPoint(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
neighbourTile); neighbourTile);
if (midPoint.succeeded()) if (midPoint.Succeeded())
{ {
neighbourNode.pos = midPoint.result; neighbourNode.pos = midPoint.result;
} }
@ -3403,7 +3403,7 @@ namespace DotRecast.Detour
vNormalize(ref hitNormal); vNormalize(ref hitNormal);
} }
return Results.success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal)); return Results.Success(new FindDistanceToWallResult((float)Math.Sqrt(radiusSqr), hitPos, hitNormal));
} }
/// Returns true if the polygon reference is valid and passes the filter restrictions. /// Returns true if the polygon reference is valid and passes the filter restrictions.
@ -3412,7 +3412,7 @@ namespace DotRecast.Detour
public bool isValidPolyRef(long refs, QueryFilter filter) public bool isValidPolyRef(long refs, QueryFilter filter)
{ {
Result<Tuple<MeshTile, Poly>> tileAndPolyResult = m_nav.getTileAndPolyByRef(refs); Result<Tuple<MeshTile, Poly>> tileAndPolyResult = m_nav.getTileAndPolyByRef(refs);
if (tileAndPolyResult.failed()) if (tileAndPolyResult.Failed())
{ {
return false; return false;
} }
@ -3447,22 +3447,22 @@ namespace DotRecast.Detour
{ {
if (!m_nav.isValidPolyRef(endRef)) if (!m_nav.isValidPolyRef(endRef))
{ {
return Results.invalidParam<List<long>>("Invalid end ref"); return Results.InvalidParam<List<long>>("Invalid end ref");
} }
List<Node> nodes = m_nodePool.findNodes(endRef); List<Node> nodes = m_nodePool.findNodes(endRef);
if (nodes.Count != 1) if (nodes.Count != 1)
{ {
return Results.invalidParam<List<long>>("Invalid end ref"); return Results.InvalidParam<List<long>>("Invalid end ref");
} }
Node endNode = nodes[0]; Node endNode = nodes[0];
if ((endNode.flags & DT_NODE_CLOSED) == 0) if ((endNode.flags & DT_NODE_CLOSED) == 0)
{ {
return Results.invalidParam<List<long>>("Invalid end ref"); return Results.InvalidParam<List<long>>("Invalid end ref");
} }
return Results.success(getPathToNode(endNode)); return Results.Success(getPathToNode(endNode));
} }
/** /**

View File

@ -35,7 +35,7 @@ namespace DotRecast.Detour
{ {
// Find steer target. // Find steer target.
Result<List<StraightPathItem>> result = navQuery.findStraightPath(startPos, endPos, path, MAX_STEER_POINTS, 0); Result<List<StraightPathItem>> result = navQuery.findStraightPath(startPos, endPos, path, MAX_STEER_POINTS, 0);
if (result.failed()) if (result.Failed())
{ {
return null; return null;
} }
@ -154,7 +154,7 @@ namespace DotRecast.Detour
List<long> neis = new List<long>(); List<long> neis = new List<long>();
Result<Tuple<MeshTile, Poly>> tileAndPoly = navQuery.getAttachedNavMesh().getTileAndPolyByRef(path[0]); Result<Tuple<MeshTile, Poly>> tileAndPoly = navQuery.getAttachedNavMesh().getTileAndPolyByRef(path[0]);
if (tileAndPoly.failed()) if (tileAndPoly.Failed())
{ {
return path; return path;
} }

View File

@ -22,47 +22,47 @@ namespace DotRecast.Detour.QueryResults
{ {
public static class Results public static class Results
{ {
public static Result<T> success<T>(T result) public static Result<T> Success<T>(T result)
{ {
return new Result<T>(result, Status.SUCCSESS, null); return new Result<T>(result, Status.SUCCSESS, null);
} }
public static Result<T> failure<T>() public static Result<T> Failure<T>()
{ {
return new Result<T>(default, Status.FAILURE, null); return new Result<T>(default, Status.FAILURE, null);
} }
public static Result<T> invalidParam<T>() public static Result<T> InvalidParam<T>()
{ {
return new Result<T>(default, Status.FAILURE_INVALID_PARAM, null); return new Result<T>(default, Status.FAILURE_INVALID_PARAM, null);
} }
public static Result<T> failure<T>(string message) public static Result<T> Failure<T>(string message)
{ {
return new Result<T>(default, Status.FAILURE, message); return new Result<T>(default, Status.FAILURE, message);
} }
public static Result<T> invalidParam<T>(string message) public static Result<T> InvalidParam<T>(string message)
{ {
return new Result<T>(default, Status.FAILURE_INVALID_PARAM, message); return new Result<T>(default, Status.FAILURE_INVALID_PARAM, message);
} }
public static Result<T> failure<T>(T result) public static Result<T> Failure<T>(T result)
{ {
return new Result<T>(result, Status.FAILURE, null); return new Result<T>(result, Status.FAILURE, null);
} }
public static Result<T> partial<T>(T result) public static Result<T> Partial<T>(T result)
{ {
return new Result<T>(default, Status.PARTIAL_RESULT, null); return new Result<T>(default, Status.PARTIAL_RESULT, null);
} }
public static Result<T> of<T>(Status status, string message) public static Result<T> Of<T>(Status status, string message)
{ {
return new Result<T>(default, status, message); return new Result<T>(default, status, message);
} }
public static Result<T> of<T>(Status status, T result) public static Result<T> Of<T>(Status status, T result)
{ {
return new Result<T>(result, status, null); return new Result<T>(result, status, null);
} }
@ -82,12 +82,12 @@ namespace DotRecast.Detour.QueryResults
} }
public bool failed() public bool Failed()
{ {
return status.isFailed(); return status.isFailed();
} }
public bool succeeded() public bool Succeeded()
{ {
return status.isSuccess(); return status.isSuccess();
} }

View File

@ -1282,7 +1282,7 @@ public class RecastDebugDraw : DebugDraw
} }
Result<Tuple<MeshTile, Poly>> tileAndPolyResult = mesh.getTileAndPolyByRef(refs); Result<Tuple<MeshTile, Poly>> tileAndPolyResult = mesh.getTileAndPolyByRef(refs);
if (tileAndPolyResult.failed()) if (tileAndPolyResult.Failed())
{ {
return; return;
} }

View File

@ -149,7 +149,7 @@ public class CrowdProfilingTool
private Vector3f? getMobPosition(NavMeshQuery navquery, QueryFilter filter) private Vector3f? getMobPosition(NavMeshQuery navquery, QueryFilter filter)
{ {
Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd); Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd);
if (result.succeeded()) if (result.Succeeded())
{ {
return result.result.getRandomPt(); return result.result.getRandomPt();
} }
@ -164,7 +164,7 @@ public class CrowdProfilingTool
int zone = (int)(rnd.frand() * zones.Count); int zone = (int)(rnd.frand() * zones.Count);
Result<FindRandomPointResult> result = navquery.findRandomPointWithinCircle(zones[zone].getRandomRef(), Result<FindRandomPointResult> result = navquery.findRandomPointWithinCircle(zones[zone].getRandomRef(),
zones[zone].getRandomPt(), zoneRadius, filter, rnd); zones[zone].getRandomPt(), zoneRadius, filter, rnd);
if (result.succeeded()) if (result.Succeeded())
{ {
return result.result.getRandomPt(); return result.result.getRandomPt();
} }
@ -184,7 +184,7 @@ public class CrowdProfilingTool
for (int k = 0; k < 100; k++) for (int k = 0; k < 100; k++)
{ {
Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd); Result<FindRandomPointResult> result = navquery.findRandomPoint(filter, rnd);
if (result.succeeded()) if (result.Succeeded())
{ {
bool valid = true; bool valid = true;
foreach (FindRandomPointResult zone in zones) foreach (FindRandomPointResult zone in zones)
@ -281,11 +281,11 @@ public class CrowdProfilingTool
{ {
// Move somewhere // Move somewhere
Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter); Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter);
if (nearestPoly.succeeded()) if (nearestPoly.Succeeded())
{ {
Result<FindRandomPointResult> result = navquery.findRandomPointAroundCircle(nearestPoly.result.getNearestRef(), Result<FindRandomPointResult> result = navquery.findRandomPointAroundCircle(nearestPoly.result.getNearestRef(),
agentData.home, zoneRadius * 2f, filter, rnd); agentData.home, zoneRadius * 2f, filter, rnd);
if (result.succeeded()) if (result.Succeeded())
{ {
crowd.requestMoveTarget(ag, result.result.getRandomRef(), result.result.getRandomPt()); crowd.requestMoveTarget(ag, result.result.getRandomRef(), result.result.getRandomPt());
} }
@ -296,11 +296,11 @@ public class CrowdProfilingTool
{ {
// Move somewhere close // Move somewhere close
Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter); Result<FindNearestPolyResult> nearestPoly = navquery.findNearestPoly(ag.npos, crowd.getQueryExtents(), filter);
if (nearestPoly.succeeded()) if (nearestPoly.Succeeded())
{ {
Result<FindRandomPointResult> result = navquery.findRandomPointAroundCircle(nearestPoly.result.getNearestRef(), Result<FindRandomPointResult> result = navquery.findRandomPointAroundCircle(nearestPoly.result.getNearestRef(),
agentData.home, zoneRadius * 0.2f, filter, rnd); agentData.home, zoneRadius * 0.2f, filter, rnd);
if (result.succeeded()) if (result.Succeeded())
{ {
crowd.requestMoveTarget(ag, result.result.getRandomRef(), result.result.getRandomPt()); crowd.requestMoveTarget(ag, result.result.getRandomRef(), result.result.getRandomPt());
} }

View File

@ -199,7 +199,7 @@ public class CrowdTool : Tool
if (refs != 0) if (refs != 0)
{ {
Result<int> flags = nav.getPolyFlags(refs); Result<int> flags = nav.getPolyFlags(refs);
if (flags.succeeded()) if (flags.Succeeded())
{ {
nav.setPolyFlags(refs, flags.result ^ SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED); nav.setPolyFlags(refs, flags.result ^ SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED);
} }

View File

@ -252,7 +252,7 @@ public class TestNavmeshTool : Tool
polys = PathUtils.fixupShortcuts(polys, m_navQuery); polys = PathUtils.fixupShortcuts(polys, m_navQuery);
Result<float> polyHeight = m_navQuery.getPolyHeight(polys[0], moveAlongSurface.getResultPos()); Result<float> polyHeight = m_navQuery.getPolyHeight(polys[0], moveAlongSurface.getResultPos());
if (polyHeight.succeeded()) if (polyHeight.Succeeded())
{ {
iterPos[1] = polyHeight.result; iterPos[1] = polyHeight.result;
} }
@ -288,7 +288,7 @@ public class TestNavmeshTool : Tool
// Handle the connection. // Handle the connection.
var offMeshCon = m_navMesh.getOffMeshConnectionPolyEndPoints(prevRef, polyRef); var offMeshCon = m_navMesh.getOffMeshConnectionPolyEndPoints(prevRef, polyRef);
if (offMeshCon.succeeded()) if (offMeshCon.Succeeded())
{ {
var startPos = offMeshCon.result.Item1; var startPos = offMeshCon.result.Item1;
var endPos = offMeshCon.result.Item2; var endPos = offMeshCon.result.Item2;
@ -336,7 +336,7 @@ public class TestNavmeshTool : Tool
{ {
Result<ClosestPointOnPolyResult> result = m_navQuery Result<ClosestPointOnPolyResult> result = m_navQuery
.closestPointOnPoly(m_polys[m_polys.Count - 1], m_epos); .closestPointOnPoly(m_polys[m_polys.Count - 1], m_epos);
if (result.succeeded()) if (result.Succeeded())
{ {
epos = result.result.getClosest(); epos = result.result.getClosest();
} }
@ -368,7 +368,7 @@ public class TestNavmeshTool : Tool
{ {
{ {
Result<RaycastHit> hit = m_navQuery.raycast(m_startRef, m_spos, m_epos, m_filter, 0, 0); Result<RaycastHit> hit = m_navQuery.raycast(m_startRef, m_spos, m_epos, m_filter, 0, 0);
if (hit.succeeded()) if (hit.Succeeded())
{ {
m_polys = hit.result.path; m_polys = hit.result.path;
if (hit.result.t > 1) if (hit.result.t > 1)
@ -390,7 +390,7 @@ public class TestNavmeshTool : Tool
{ {
Result<float> result = m_navQuery Result<float> result = m_navQuery
.getPolyHeight(hit.result.path[hit.result.path.Count - 1], m_hitPos); .getPolyHeight(hit.result.path[hit.result.path.Count - 1], m_hitPos);
if (result.succeeded()) if (result.Succeeded())
{ {
m_hitPos[1] = result.result; m_hitPos[1] = result.result;
} }
@ -411,7 +411,7 @@ public class TestNavmeshTool : Tool
m_distanceToWall = 0.0f; m_distanceToWall = 0.0f;
Result<FindDistanceToWallResult> result = m_navQuery.findDistanceToWall(m_startRef, m_spos, 100.0f, Result<FindDistanceToWallResult> result = m_navQuery.findDistanceToWall(m_startRef, m_spos, 100.0f,
m_filter); m_filter);
if (result.succeeded()) if (result.Succeeded())
{ {
m_distanceToWall = result.result.getDistance(); m_distanceToWall = result.result.getDistance();
m_hitPos = result.result.getPosition(); m_hitPos = result.result.getPosition();
@ -428,7 +428,7 @@ public class TestNavmeshTool : Tool
float dist = (float)Math.Sqrt(dx * dx + dz * dz); float dist = (float)Math.Sqrt(dx * dx + dz * dz);
Result<FindPolysAroundResult> result = m_navQuery.findPolysAroundCircle(m_startRef, m_spos, dist, Result<FindPolysAroundResult> result = m_navQuery.findPolysAroundCircle(m_startRef, m_spos, dist,
m_filter); m_filter);
if (result.succeeded()) if (result.Succeeded())
{ {
m_polys = result.result.getRefs(); m_polys = result.result.getRefs();
m_parent = result.result.getParentRefs(); m_parent = result.result.getParentRefs();
@ -460,7 +460,7 @@ public class TestNavmeshTool : Tool
m_queryPoly[11] = m_epos[2] + nz; m_queryPoly[11] = m_epos[2] + nz;
Result<FindPolysAroundResult> result = m_navQuery.findPolysAroundShape(m_startRef, m_queryPoly, m_filter); Result<FindPolysAroundResult> result = m_navQuery.findPolysAroundShape(m_startRef, m_queryPoly, m_filter);
if (result.succeeded()) if (result.Succeeded())
{ {
m_polys = result.result.getRefs(); m_polys = result.result.getRefs();
m_parent = result.result.getParentRefs(); m_parent = result.result.getParentRefs();
@ -474,7 +474,7 @@ public class TestNavmeshTool : Tool
m_neighbourhoodRadius = m_sample.getSettingsUI().getAgentRadius() * 20.0f; m_neighbourhoodRadius = m_sample.getSettingsUI().getAgentRadius() * 20.0f;
Result<FindLocalNeighbourhoodResult> result = m_navQuery.findLocalNeighbourhood(m_startRef, m_spos, Result<FindLocalNeighbourhoodResult> result = m_navQuery.findLocalNeighbourhood(m_startRef, m_spos,
m_neighbourhoodRadius, m_filter); m_neighbourhoodRadius, m_filter);
if (result.succeeded()) if (result.Succeeded())
{ {
m_polys = result.result.getRefs(); m_polys = result.result.getRefs();
m_parent = result.result.getParentRefs(); m_parent = result.result.getParentRefs();
@ -496,7 +496,7 @@ public class TestNavmeshTool : Tool
{ {
Result<FindRandomPointResult> result = m_navQuery.findRandomPointAroundCircle(m_startRef, m_spos, dist, Result<FindRandomPointResult> result = m_navQuery.findRandomPointAroundCircle(m_startRef, m_spos, dist,
m_filter, new FRand(), constraint); m_filter, new FRand(), constraint);
if (result.succeeded()) if (result.Succeeded())
{ {
randomPoints.Add(result.result.getRandomPt()); randomPoints.Add(result.result.getRandomPt());
} }
@ -840,7 +840,7 @@ public class TestNavmeshTool : Tool
{ {
Result<GetPolyWallSegmentsResult> result = m_sample.getNavMeshQuery() Result<GetPolyWallSegmentsResult> result = m_sample.getNavMeshQuery()
.getPolyWallSegments(m_polys[i], false, m_filter); .getPolyWallSegments(m_polys[i], false, m_filter);
if (result.succeeded()) if (result.Succeeded())
{ {
dd.begin(LINES, 2.0f); dd.begin(LINES, 2.0f);
GetPolyWallSegmentsResult wallSegments = result.result; GetPolyWallSegmentsResult wallSegments = result.result;
@ -951,7 +951,7 @@ public class TestNavmeshTool : Tool
Vector3f center = Vector3f.Zero; Vector3f center = Vector3f.Zero;
Result<Tuple<MeshTile, Poly>> tileAndPoly = navMesh.getTileAndPolyByRef(refs); Result<Tuple<MeshTile, Poly>> tileAndPoly = navMesh.getTileAndPolyByRef(refs);
if (tileAndPoly.succeeded()) if (tileAndPoly.Succeeded())
{ {
MeshTile tile = tileAndPoly.result.Item1; MeshTile tile = tileAndPoly.result.Item1;
Poly poly = tileAndPoly.result.Item2; Poly poly = tileAndPoly.result.Item2;
@ -996,7 +996,7 @@ public class TestNavmeshTool : Tool
{ {
Result<ClosestPointOnPolyResult> result = m_navQuery Result<ClosestPointOnPolyResult> result = m_navQuery
.closestPointOnPoly(m_polys[m_polys.Count - 1], m_epos); .closestPointOnPoly(m_polys[m_polys.Count - 1], m_epos);
if (result.succeeded()) if (result.Succeeded())
{ {
epos = result.result.getClosest(); epos = result.result.getClosest();
} }
@ -1005,7 +1005,7 @@ public class TestNavmeshTool : Tool
{ {
Result<List<StraightPathItem>> result = m_navQuery.findStraightPath(m_spos, epos, m_polys, Result<List<StraightPathItem>> result = m_navQuery.findStraightPath(m_spos, epos, m_polys,
MAX_POLYS, NavMeshQuery.DT_STRAIGHTPATH_ALL_CROSSINGS); MAX_POLYS, NavMeshQuery.DT_STRAIGHTPATH_ALL_CROSSINGS);
if (result.succeeded()) if (result.Succeeded())
{ {
m_straightPath = result.result; m_straightPath = result.result;
} }

View File

@ -44,7 +44,7 @@ public class PathCorridorTest
straightPath.Add(new StraightPathItem(Vector3f.Of(12, 20, 30.00002f), 0, 0)); straightPath.Add(new StraightPathItem(Vector3f.Of(12, 20, 30.00002f), 0, 0));
straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0)); straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0));
straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0)); straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0));
Result<List<StraightPathItem>> result = Results.success(straightPath); Result<List<StraightPathItem>> result = Results.Success(straightPath);
var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>()); var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>());
mockQuery.Setup(q => q.findStraightPath( mockQuery.Setup(q => q.findStraightPath(
It.IsAny<Vector3f>(), It.IsAny<Vector3f>(),
@ -67,7 +67,7 @@ public class PathCorridorTest
straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0)); straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), 0, 0));
straightPath.Add(new StraightPathItem(Vector3f.Of(12f, 22, 33f), NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh straightPath.Add(new StraightPathItem(Vector3f.Of(12f, 22, 33f), NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh straightPath.Add(new StraightPathItem(Vector3f.Of(11f, 21, 32f), NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
Result<List<StraightPathItem>> result = Results.success(straightPath); Result<List<StraightPathItem>> result = Results.Success(straightPath);
var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>()); var mockQuery = new Mock<NavMeshQuery>(It.IsAny<NavMesh>());
var s = mockQuery.Setup(q => q.findStraightPath( var s = mockQuery.Setup(q => q.findStraightPath(

View File

@ -110,7 +110,7 @@ public class UnityAStarPathfindingImporterTest
{ {
Vector3f position = positions[i]; Vector3f position = positions[i];
Result<FindNearestPolyResult> result = query.findNearestPoly(position, extents, filter); Result<FindNearestPolyResult> result = query.findNearestPoly(position, extents, filter);
Assert.That(result.succeeded(), Is.True); Assert.That(result.Succeeded(), Is.True);
Assert.That(result.result.getNearestPos(), Is.Not.EqualTo(Vector3f.Zero), "Nearest start position is null!"); Assert.That(result.result.getNearestPos(), Is.Not.EqualTo(Vector3f.Zero), "Nearest start position is null!");
results[i] = result.result; results[i] = result.result;
} }

View File

@ -43,7 +43,7 @@ public class FindNearestPolyTest : AbstractDetourTest
{ {
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindNearestPolyResult> poly = query.findNearestPoly(startPos, extents, filter); Result<FindNearestPolyResult> poly = query.findNearestPoly(startPos, extents, filter);
Assert.That(poly.succeeded(), Is.True); Assert.That(poly.Succeeded(), Is.True);
Assert.That(poly.result.getNearestRef(), Is.EqualTo(POLY_REFS[i])); Assert.That(poly.result.getNearestRef(), Is.EqualTo(POLY_REFS[i]));
for (int v = 0; v < POLY_POS[i].Length; v++) for (int v = 0; v < POLY_POS[i].Length; v++)
{ {
@ -75,7 +75,7 @@ public class FindNearestPolyTest : AbstractDetourTest
{ {
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindNearestPolyResult> poly = query.findNearestPoly(startPos, extents, filter); Result<FindNearestPolyResult> poly = query.findNearestPoly(startPos, extents, filter);
Assert.That(poly.succeeded(), Is.True); Assert.That(poly.Succeeded(), Is.True);
Assert.That(poly.result.getNearestRef(), Is.EqualTo(0L)); Assert.That(poly.result.getNearestRef(), Is.EqualTo(0L));
for (int v = 0; v < POLY_POS[i].Length; v++) for (int v = 0; v < POLY_POS[i].Length; v++)
{ {

View File

@ -107,7 +107,7 @@ public class FindPolysAroundCircleTest : AbstractDetourTest
long startRef = startRefs[i]; long startRef = startRefs[i];
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Result<FindPolysAroundResult> result = query.findPolysAroundCircle(startRef, startPos, 7.5f, filter); Result<FindPolysAroundResult> result = query.findPolysAroundCircle(startRef, startPos, 7.5f, filter);
Assert.That(result.succeeded(), Is.True); Assert.That(result.Succeeded(), Is.True);
FindPolysAroundResult polys = result.result; FindPolysAroundResult polys = result.result;
Assert.That(polys.getRefs().Count, Is.EqualTo(REFS[i].Length)); Assert.That(polys.getRefs().Count, Is.EqualTo(REFS[i].Length));
for (int v = 0; v < REFS[i].Length; v++) for (int v = 0; v < REFS[i].Length; v++)

View File

@ -75,7 +75,7 @@ public class MoveAlongSurfaceTest : AbstractDetourTest
Vector3f startPos = startPoss[i]; Vector3f startPos = startPoss[i];
Vector3f endPos = endPoss[i]; Vector3f endPos = endPoss[i];
Result<MoveAlongSurfaceResult> result = query.moveAlongSurface(startRef, startPos, endPos, filter); Result<MoveAlongSurfaceResult> result = query.moveAlongSurface(startRef, startPos, endPos, filter);
Assert.That(result.succeeded(), Is.True); Assert.That(result.Succeeded(), Is.True);
MoveAlongSurfaceResult path = result.result; MoveAlongSurfaceResult path = result.result;
for (int v = 0; v < 3; v++) for (int v = 0; v < 3; v++)
{ {

View File

@ -36,7 +36,7 @@ public class RandomPointTest : AbstractDetourTest
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
{ {
Result<FindRandomPointResult> point = query.findRandomPoint(filter, f); Result<FindRandomPointResult> point = query.findRandomPoint(filter, f);
Assert.That(point.succeeded(), Is.True); Assert.That(point.Succeeded(), Is.True);
Tuple<MeshTile, Poly> tileAndPoly = navmesh.getTileAndPolyByRef(point.result.getRandomRef()).result; Tuple<MeshTile, Poly> tileAndPoly = navmesh.getTileAndPolyByRef(point.result.getRandomRef()).result;
float[] bmin = new float[2]; float[] bmin = new float[2];
float[] bmax = new float[2]; float[] bmax = new float[2];
@ -66,7 +66,7 @@ public class RandomPointTest : AbstractDetourTest
{ {
Result<FindRandomPointResult> result = query.findRandomPointAroundCircle(point.getRandomRef(), point.getRandomPt(), Result<FindRandomPointResult> result = query.findRandomPointAroundCircle(point.getRandomRef(), point.getRandomPt(),
5f, filter, f); 5f, filter, f);
Assert.That(result.failed(), Is.False); Assert.That(result.Failed(), Is.False);
point = result.result; point = result.result;
Tuple<MeshTile, Poly> tileAndPoly = navmesh.getTileAndPolyByRef(point.getRandomRef()).result; Tuple<MeshTile, Poly> tileAndPoly = navmesh.getTileAndPolyByRef(point.getRandomRef()).result;
float[] bmin = new float[2]; float[] bmin = new float[2];
@ -98,7 +98,7 @@ public class RandomPointTest : AbstractDetourTest
{ {
Result<FindRandomPointResult> result = query.findRandomPointWithinCircle(point.getRandomRef(), point.getRandomPt(), Result<FindRandomPointResult> result = query.findRandomPointWithinCircle(point.getRandomRef(), point.getRandomPt(),
radius, filter, f); radius, filter, f);
Assert.That(result.failed(), Is.False); Assert.That(result.Failed(), Is.False);
float distance = vDist2D(point.getRandomPt(), result.result.getRandomPt()); float distance = vDist2D(point.getRandomPt(), result.result.getRandomPt());
Assert.That(distance <= radius, Is.True); Assert.That(distance <= radius, Is.True);
point = result.result; point = result.result;