📄 be_aas_route.c
字号:
portalnum = aasworld.portalindex[cluster->firstportal + i];
portal = &aasworld.portals[portalnum];
//if this is the portal of the current update continue
if (portal->areanum == curupdate->areanum) continue;
//
clusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum);
if (clusterareanum >= cluster->numreachabilityareas) continue;
//
t = cache->traveltimes[clusterareanum];
if (!t) continue;
t += curupdate->tmptraveltime;
//
if (!portalcache->traveltimes[portalnum] ||
portalcache->traveltimes[portalnum] > t)
{
portalcache->traveltimes[portalnum] = t;
nextupdate = &aasworld.portalupdate[portalnum];
if (portal->frontcluster == curupdate->cluster)
{
nextupdate->cluster = portal->backcluster;
} //end if
else
{
nextupdate->cluster = portal->frontcluster;
} //end else
nextupdate->areanum = portal->areanum;
//add travel time through the actual portal area for the next update
nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum];
if (!nextupdate->inlist)
{
// we add the update to the end of the list
// we could also use a B+ tree to have a real sorted list
// on travel time which makes for faster routing updates
nextupdate->next = NULL;
nextupdate->prev = updatelistend;
if (updatelistend) updatelistend->next = nextupdate;
else updateliststart = nextupdate;
updatelistend = nextupdate;
nextupdate->inlist = qtrue;
} //end if
} //end if
} //end for
} //end while
} //end of the function AAS_UpdatePortalRoutingCache
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags)
{
aas_routingcache_t *cache;
//find the cached portal routing if existing
for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next)
{
if (cache->travelflags == travelflags) break;
} //end for
//if the portal routing isn't cached
if (!cache)
{
cache = AAS_AllocRoutingCache(aasworld.numportals);
cache->cluster = clusternum;
cache->areanum = areanum;
VectorCopy(aasworld.areas[areanum].center, cache->origin);
cache->starttraveltime = 1;
cache->travelflags = travelflags;
//add the cache to the cache list
cache->prev = NULL;
cache->next = aasworld.portalcache[areanum];
if (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache;
aasworld.portalcache[areanum] = cache;
//update the cache
AAS_UpdatePortalRoutingCache(cache);
} //end if
else
{
AAS_UnlinkCache(cache);
} //end else
//the cache has been accessed
cache->time = AAS_RoutingTime();
cache->type = CACHETYPE_PORTAL;
AAS_LinkCache(cache);
return cache;
} //end of the function AAS_GetPortalRoutingCache
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum)
{
int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum;
unsigned short int t, besttime;
aas_portal_t *portal;
aas_cluster_t *cluster;
aas_routingcache_t *areacache, *portalcache;
aas_reachability_t *reach;
if (!aasworld.initialized) return qfalse;
if (areanum == goalareanum)
{
*traveltime = 1;
*reachnum = 0;
return qtrue;
}
//
if (areanum <= 0 || areanum >= aasworld.numareas)
{
if (bot_developer)
{
botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum);
} //end if
return qfalse;
} //end if
if (goalareanum <= 0 || goalareanum >= aasworld.numareas)
{
if (bot_developer)
{
botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum);
} //end if
return qfalse;
} //end if
// make sure the routing cache doesn't grow to large
while(AvailableMemory() < 1 * 1024 * 1024) {
if (!AAS_FreeOldestCache()) break;
}
//
if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum))
{
travelflags |= TFL_DONOTENTER;
} //end if
//NOTE: the number of routing updates is limited per frame
/*
if (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES)
{
#ifdef DEBUG
//Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed");
#endif
return 0;
} //end if
*/
//
clusternum = aasworld.areasettings[areanum].cluster;
goalclusternum = aasworld.areasettings[goalareanum].cluster;
//check if the area is a portal of the goal area cluster
if (clusternum < 0 && goalclusternum > 0)
{
portal = &aasworld.portals[-clusternum];
if (portal->frontcluster == goalclusternum ||
portal->backcluster == goalclusternum)
{
clusternum = goalclusternum;
} //end if
} //end if
//check if the goalarea is a portal of the area cluster
else if (clusternum > 0 && goalclusternum < 0)
{
portal = &aasworld.portals[-goalclusternum];
if (portal->frontcluster == clusternum ||
portal->backcluster == clusternum)
{
goalclusternum = clusternum;
} //end if
} //end if
//if both areas are in the same cluster
//NOTE: there might be a shorter route via another cluster!!! but we don't care
if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum)
{
//
areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags);
//the number of the area in the cluster
clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
//the cluster the area is in
cluster = &aasworld.clusters[clusternum];
//if the area is NOT a reachability area
if (clusterareanum >= cluster->numreachabilityareas) return 0;
//if it is possible to travel to the goal area through this cluster
if (areacache->traveltimes[clusterareanum] != 0)
{
*reachnum = aasworld.areasettings[areanum].firstreachablearea +
areacache->reachabilities[clusterareanum];
if (!origin) {
*traveltime = areacache->traveltimes[clusterareanum];
return qtrue;
}
reach = &aasworld.reachability[*reachnum];
*traveltime = areacache->traveltimes[clusterareanum] +
AAS_AreaTravelTime(areanum, origin, reach->start);
//
return qtrue;
} //end if
} //end if
//
clusternum = aasworld.areasettings[areanum].cluster;
goalclusternum = aasworld.areasettings[goalareanum].cluster;
//if the goal area is a portal
if (goalclusternum < 0)
{
//just assume the goal area is part of the front cluster
portal = &aasworld.portals[-goalclusternum];
goalclusternum = portal->frontcluster;
} //end if
//get the portal routing cache
portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags);
//if the area is a cluster portal, read directly from the portal cache
if (clusternum < 0)
{
*traveltime = portalcache->traveltimes[-clusternum];
*reachnum = aasworld.areasettings[areanum].firstreachablearea +
portalcache->reachabilities[-clusternum];
return qtrue;
} //end if
//
besttime = 0;
bestreachnum = -1;
//the cluster the area is in
cluster = &aasworld.clusters[clusternum];
//find the portal of the area cluster leading towards the goal area
for (i = 0; i < cluster->numportals; i++)
{
portalnum = aasworld.portalindex[cluster->firstportal + i];
//if the goal area isn't reachable from the portal
if (!portalcache->traveltimes[portalnum]) continue;
//
portal = &aasworld.portals[portalnum];
//get the cache of the portal area
areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags);
//current area inside the current cluster
clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
//if the area is NOT a reachability area
if (clusterareanum >= cluster->numreachabilityareas) continue;
//if the portal is NOT reachable from this area
if (!areacache->traveltimes[clusterareanum]) continue;
//total travel time is the travel time the portal area is from
//the goal area plus the travel time towards the portal area
t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];
//FIXME: add the exact travel time through the actual portal area
//NOTE: for now we just add the largest travel time through the portal area
// because we can't directly calculate the exact travel time
// to be more specific we don't know which reachability was used to travel
// into the portal area
t += aasworld.portalmaxtraveltimes[portalnum];
//
if (origin)
{
*reachnum = aasworld.areasettings[areanum].firstreachablearea +
areacache->reachabilities[clusterareanum];
reach = aasworld.reachability + *reachnum;
t += AAS_AreaTravelTime(areanum, origin, reach->start);
} //end if
//if the time is better than the one already found
if (!besttime || t < besttime)
{
bestreachnum = *reachnum;
besttime = t;
} //end if
} //end for
if (bestreachnum < 0) {
return qfalse;
}
*reachnum = bestreachnum;
*traveltime = besttime;
return qtrue;
} //end of the function AAS_AreaRouteToGoalArea
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
{
int traveltime, reachnum;
if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
{
return traveltime;
}
return 0;
} //end of the function AAS_AreaTravelTimeToGoalArea
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
{
int traveltime, reachnum;
if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
{
return reachnum;
}
return 0;
} //end of the function AAS_AreaReachabilityToGoalArea
//===========================================================================
// predict the route and stop on one of the stop events
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,
int goalareanum, int travelflags, int maxareas, int maxtime,
int stopevent, int stopcontents, int stoptfl, int stopareanum)
{
int curareanum, reachnum, i, j, testareanum;
vec3_t curorigin;
aas_reachability_t *reach;
aas_reachabilityareas_t *reachareas;
//init output
route->stopevent = RSE_NONE;
route->endarea = goalareanum;
route->endcontents = 0;
route->endtravelflags = 0;
VectorCopy(origin, route->endpos);
route->time = 0;
curareanum = areanum;
VectorCopy(origin, curorigin);
for (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++)
{
reachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags);
if (!reachnum)
{
route->stopevent = RSE_NOROUTE;
return qfalse;
} //end if
reach = &aasworld.reachability[reachnum];
//
if (stopevent & RSE_USETRAVELTYPE)
{
if (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl)
{
route->stopevent = RSE_USETRAVELTYPE;
route->endarea = curareanum;
route->endcontents = aasworld.areasettings[curareanum].contents;
route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
VectorCopy(reach->start, route->endpos);
return qtrue;
} //end if
if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl)
{
route->stopevent = RSE_USETRAVELTYPE;
route->endarea = reach->areanum;
route->endcontents = aasworld.areasettings[reach->areanum].contents;
route->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum);
VectorCopy(reach->end, route->endpos);
route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
route->time += reach->traveltime;
return qtrue;
} //end if
} //end if
reachareas = &aasworld.reachabilityareas[reachnum];
for (j = 0; j < reachareas->numareas + 1; j++)
{
if (j >= reachareas->numareas)
testareanum = reach->areanum;
else
testareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j];
if (stopevent & RSE_ENTERCONTENTS)
{
if (aasworld.areasettings[testareanum].contents & stopcontents)
{
route->stopevent =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -