//===========================================================================
//	free permanent memory used by route-table system
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_RT_ShutdownRouteTable( void ) {
	if ( !aasworld->routetable ) {
		return;
	}

	// free the dynamic lists
	AAS_RT_FreeMemory( aasworld->routetable->areaChildIndexes );
	AAS_RT_FreeMemory( aasworld->routetable->children );
	AAS_RT_FreeMemory( aasworld->routetable->parents );
	AAS_RT_FreeMemory( aasworld->routetable->parentChildren );
	AAS_RT_FreeMemory( aasworld->routetable->visibleParents );
//	AAS_RT_FreeMemory( aasworld->routetable->localRoutes );
//	AAS_RT_FreeMemory( aasworld->routetable->parentRoutes );
	AAS_RT_FreeMemory( aasworld->routetable->parentLinks );
//	AAS_RT_FreeMemory( aasworld->routetable->routeIndexes );
//	AAS_RT_FreeMemory( aasworld->routetable->parentTravelTimes );

	// kill the table
	AAS_RT_FreeMemory( aasworld->routetable );
	aasworld->routetable = NULL;
}
Ejemplo n.º 2
0
void AAS_RT_BuildRouteTable(void)
{
	int                i, j, k;
	aas_area_t         *srcarea;
	aas_areasettings_t *srcsettings;
//	vec3_t	vec;
	unsigned int totalcount;
	unsigned int noroutecount;

	aas_area_buildlocalinfo_t **area_localinfos;
	aas_area_buildlocalinfo_t *localinfo;

	aas_area_childlocaldata_t **area_childlocaldata;
	aas_area_childlocaldata_t *child;

	aas_area_parent_t *area_parents[MAX_PARENTS];
	aas_area_parent_t *thisparent;

	int bestchild, bestcount, bestparent, cnt;

	int memoryend;

	unsigned short int *visibleParents;

#ifdef CHECK_TRAVEL_TIMES
	aas_rt_route_t     **filteredroutetable;
	unsigned short int traveltime;
#endif

	fileHandle_t fp;
	char         filename[MAX_QPATH];

// not used anymore
	return;

	// create the routetable in this aasworld
	aasworld->routetable = (aas_rt_t *) AAS_RT_GetClearedMemory(sizeof(aas_rt_t));

	// Try to load in a prepared route-table
	Com_sprintf(filename, MAX_QPATH, "maps/%s.rtb", (*aasworld).mapname);
	botimport.Print(PRT_MESSAGE, "\n---------------------------------\n");
	botimport.Print(PRT_MESSAGE, "\ntrying to load %s\n", filename);
	botimport.FS_FOpenFile(filename, &fp, FS_READ);
	if (fp)
	{
		// read in the table..
		if (AAS_RT_ReadRouteTable(fp))
		{
			AAS_RT_PrintMemoryUsage();

			botimport.Print(PRT_MESSAGE, "\nAAS Route-Table loaded.\n");
			botimport.Print(PRT_MESSAGE, "---------------------------------\n\n");
			return;
		}
		else
		{
			botimport.Print(PRT_MESSAGE, "\nUnable to load %s, building route-table..\n", filename);
		}
	}
	else
	{
		botimport.Print(PRT_MESSAGE, "file not found, building route-table\n\n");
	}


	botimport.Print(PRT_MESSAGE, "\n-------------------------------------\nRoute-table memory usage figures..\n\n");

	totalcount   = 0;
	childcount   = 0;
	noroutecount = 0;
	childcount   = 0;
	num_parents  = 0;

	memorycount = 0;
	cachememory = 0;

	filtered_areas     = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int));
	rev_filtered_areas = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int));

	// to speed things up, build a list of FILTERED areas first
	// do this so we can check for filtered areas
	AAS_CreateAllRoutingCache();
	for (i = 0; i < (*aasworld).numareas; i++)
	{
		srcarea     = &(*aasworld).areas[i];
		srcsettings = &(*aasworld).areasettings[i];

#ifdef FILTERAREAS
		if (!(srcsettings->areaflags & (AREA_USEFORROUTING)))
		{
			continue;
		}
		if (!(srcsettings->areaflags & (AREA_GROUNDED | AREA_LIQUID | AREA_LADDER)))
		{
			continue;
		}
#endif

		rev_filtered_areas[i]        = childcount + 1;
		filtered_areas[childcount++] = (unsigned short int)i;
	}

#ifdef CHECK_TRAVEL_TIMES
	// allocate and calculate the travel times
	filteredroutetable = (aas_rt_route_t **) AAS_RT_GetClearedMemory(childcount * sizeof(aas_rt_route_t *));
	for (i = 0; i < childcount; i++)
		filteredroutetable[i] = (aas_rt_route_t *) AAS_RT_GetClearedMemory(childcount * sizeof(aas_rt_route_t));

	AAS_RT_CalculateRouteTable(filteredroutetable);

#endif  // CHECK_TRAVEL_TIMES

	// allocate for the temporary build local data
	area_localinfos = (aas_area_buildlocalinfo_t **) AAS_RT_GetClearedMemory(childcount * sizeof(aas_area_buildlocalinfo_t *));

	for (i = 0; i < childcount; i++)
	{
		srcarea     = &(*aasworld).areas[filtered_areas[i]];
		srcsettings = &(*aasworld).areasettings[filtered_areas[i]];

		// allocate memory for this area
		area_localinfos[i] = (aas_area_buildlocalinfo_t *) AAS_RT_GetClearedMemory(sizeof(aas_area_buildlocalinfo_t));
		localinfo          = area_localinfos[i];

		for (j = 0; j < childcount; j++)
		{
			if (i == j)
			{
				continue;
			}

#ifdef CHECK_TRAVEL_TIMES

			// make sure travel time is reasonable
			// Get the travel time from i to j
			traveltime = (int)filteredroutetable[i][j].travel_time;

			if (!traveltime)
			{
				noroutecount++;
				continue;
			}
			if (traveltime > MAX_LOCALTRAVELTIME)
			{
				continue;
			}

#endif  // CHECK_TRAVEL_TIMES

			// Add it to the list
			localinfo->visible[localinfo->numvisible++] = j;
			totalcount++;

			if (localinfo->numvisible >= MAX_VISIBLE_AREAS)
			{
				botimport.Print(PRT_MESSAGE, "MAX_VISIBLE_AREAS exceeded, lower MAX_VISIBLE_RANGE\n");
				break;
			}
		}
	}

	// now calculate the best list of locale's

	// allocate for the long-term child data
	area_childlocaldata = (aas_area_childlocaldata_t **) AAS_RT_GetClearedMemory(childcount * sizeof(aas_area_childlocaldata_t *));

	for (i = 0; i < childcount; i++)
	{
		area_childlocaldata[i]          = (aas_area_childlocaldata_t *) AAS_RT_GetClearedMemory(sizeof(aas_area_childlocaldata_t));
		area_childlocaldata[i]->areanum = filtered_areas[i];
	}

	while (1)
	{
		bestchild = -1;
		bestcount = 99999;

		// find the area with the least number of visible areas
		for (i = 0; i < childcount; i++)
		{
			if (area_childlocaldata[i]->parentlink)
			{
				continue;   // already has been allocated to a parent

			}
			cnt = AAS_RT_GetValidVisibleAreasCount(area_localinfos[i], area_childlocaldata);

			if (cnt < bestcount)
			{
				bestcount = area_localinfos[i]->numvisible;
				bestchild = i;
			}
		}

		if (bestchild < 0)
		{
			break;      // our job is done


		}
		localinfo = area_localinfos[bestchild];


		// look through this area's list of visible areas, and pick the one with the most VALID visible areas
		bestparent = bestchild;

		for (i = 0; i < localinfo->numvisible; i++)
		{
			if (area_childlocaldata[localinfo->visible[i]]->parentlink)
			{
				continue;   // already has been allocated to a parent

			}
			// calculate how many of children are valid
			cnt = AAS_RT_GetValidVisibleAreasCount(area_localinfos[localinfo->visible[i]], area_childlocaldata);

			if (cnt > bestcount)
			{
				bestcount  = cnt;
				bestparent = localinfo->visible[i];
			}
		}

		// now setup this parent, and assign all it's children
		localinfo = area_localinfos[bestparent];

		// we use all children now, not just valid ones
		bestcount = localinfo->numvisible;

		area_parents[num_parents] = (aas_area_parent_t *) AAS_RT_GetClearedMemory(sizeof(aas_area_parent_t));
		thisparent                = area_parents[num_parents];

		thisparent->areanum  = filtered_areas[bestparent];
		thisparent->children = (unsigned short int *) AAS_RT_GetClearedMemory((localinfo->numvisible + 1) * sizeof(unsigned short int));

		// first, add itself to the list (yes, a parent is a child of itself)
		child = area_childlocaldata[bestparent];
		AAS_RT_AddParentLink(child, num_parents, thisparent->numchildren);
		thisparent->children[thisparent->numchildren++] = filtered_areas[bestparent];

		// loop around all the parent's visible list, and make them children if they're aren't already assigned to a parent
		for (i = 0; i < localinfo->numvisible; i++)
		{
			// create the childlocaldata
			child = area_childlocaldata[localinfo->visible[i]];

			// Ridah, only one parent per child in the new system
			if (child->parentlink)
			{
				continue;   // already has been allocated to a parent

			}
			if (child->areanum != thisparent->areanum)
			{
				AAS_RT_AddParentLink(child, num_parents, thisparent->numchildren);
				thisparent->children[thisparent->numchildren++] = filtered_areas[localinfo->visible[i]];
			}
		}

		// now setup the list of children and the route-tables
		for (i = 0; i < thisparent->numchildren; i++)
		{
			child     = area_childlocaldata[-1 + rev_filtered_areas[thisparent->children[i]]];
			localinfo = area_localinfos[-1 + rev_filtered_areas[thisparent->children[i]]];

			child->parentlink->routeindexes = (unsigned short int *) AAS_RT_GetClearedMemory(thisparent->numchildren * sizeof(unsigned short int));

			// now setup the indexes
			for (j = 0; j < thisparent->numchildren; j++)
			{
				// find this child in our list of visibles
				if (j == child->parentlink->childindex)
				{
					continue;
				}

				for (k = 0; k < localinfo->numvisible; k++)
				{
					if (thisparent->children[j] == filtered_areas[localinfo->visible[k]])     // found a match
					{
						child->parentlink->routeindexes[j] = (unsigned short int)k;
						break;
					}
				}

				if (k == localinfo->numvisible)     // didn't find it, so add it to our list
				{
					if (localinfo->numvisible >= MAX_VISIBLE_AREAS)
					{
						botimport.Print(PRT_MESSAGE, "MAX_VISIBLE_AREAS exceeded, lower MAX_VISIBLE_RANGE\n");
					}
					else
					{
						localinfo->visible[localinfo->numvisible] = -1 + rev_filtered_areas[thisparent->children[j]];
						child->parentlink->routeindexes[j]        = (unsigned short int)localinfo->numvisible;
						localinfo->numvisible++;
					}
				}
			}
		}

		num_parents++;
	}

	// place all the visible areas from each child, into their childlocaldata route-table
	for (i = 0; i < childcount; i++)
	{
		localinfo = area_localinfos[i];
		child     = area_childlocaldata[i];

		child->numlocal    = localinfo->numvisible;
		child->localroutes = (aas_rt_route_t *) AAS_RT_GetClearedMemory(localinfo->numvisible * sizeof(aas_rt_route_t));

		for (j = 0; j < localinfo->numvisible; j++)
		{
			child->localroutes[j] = filteredroutetable[i][localinfo->visible[j]];
		}

		child->parentroutes = (aas_rt_route_t *) AAS_RT_GetClearedMemory(num_parents * sizeof(aas_rt_route_t));

		for (j = 0; j < num_parents; j++)
		{
			child->parentroutes[j] = filteredroutetable[i][-1 + rev_filtered_areas[area_parents[j]->areanum]];
		}
	}

	// build the visibleParents lists
	visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(num_parents * sizeof(unsigned short int));
	for (i = 0; i < num_parents; i++)
	{
		area_parents[i]->numVisibleParents = 0;

		for (j = 0; j < num_parents; j++)
		{
			if (i == j)
			{
				continue;
			}

			if (!AAS_inPVS((*aasworld).areas[area_parents[i]->areanum].center, (*aasworld).areas[area_parents[j]->areanum].center))
			{
				continue;
			}

			visibleParents[area_parents[i]->numVisibleParents] = j;
			area_parents[i]->numVisibleParents++;
		}

		// now copy the list over to the current src area
		area_parents[i]->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory(area_parents[i]->numVisibleParents * sizeof(unsigned short int));
		memcpy(area_parents[i]->visibleParents, visibleParents, area_parents[i]->numVisibleParents * sizeof(unsigned short int));

	}
	AAS_RT_FreeMemory(visibleParents);

	// before we free the main childlocaldata, go through and assign the aas_area's to their appropriate childlocaldata
	//	this would require modification of the aas_area_t structure, so for now, we'll just place them in a global array, for external reference

//	aasworld->routetable->area_childlocaldata_list = (aas_area_childlocaldata_t **) AAS_RT_GetClearedMemory( (*aasworld).numareas * sizeof(aas_area_childlocaldata_t *) );
//	for (i=0; i<childcount; i++)
//	{
//		aasworld->routetable->area_childlocaldata_list[filtered_areas[i]] = area_childlocaldata[i];
//	}

	// copy the list of parents to a global structure for now (should eventually go into the (*aasworld) structure
//	aasworld->routetable->area_parents_global = (aas_area_parent_t **) AAS_RT_GetClearedMemory( num_parents * sizeof(aas_area_parent_t *) );
//	memcpy( aasworld->routetable->area_parents_global, area_parents, num_parents * sizeof(aas_area_parent_t *) );

	// ................................................
	// Convert the data into the correct format
	{
		aas_rt_t             *rt;
		aas_rt_child_t       *child;
		aas_rt_parent_t      *parent;
		aas_rt_parent_link_t *plink;
		unsigned short int   *psi;

		aas_area_childlocaldata_t *chloc;
		aas_area_parent_t         *apar;
		aas_parent_link_t         *oplink;

		int localRoutesCount, parentRoutesCount, parentChildrenCount, visibleParentsCount, parentLinkCount, routeIndexesCount;

		rt                  = (*aasworld).routetable;
		localRoutesCount    = 0;
		parentRoutesCount   = 0;
		parentChildrenCount = 0;
		visibleParentsCount = 0;
		parentLinkCount     = 0;
		routeIndexesCount   = 0;

		// areaChildIndexes
		rt->areaChildIndexes = (unsigned short int *) AAS_RT_GetClearedMemory((*aasworld).numareas * sizeof(unsigned short int));
		for (i = 0; i < childcount; i++)
		{
			rt->areaChildIndexes[filtered_areas[i]] = i + 1;
		}

		// children
		rt->numChildren = childcount;
		rt->children    = (aas_rt_child_t *) AAS_RT_GetClearedMemory(rt->numChildren * sizeof(aas_rt_child_t));
		child           = rt->children;
		for (i = 0; i < childcount; i++, child++)
		{
			chloc = area_childlocaldata[i];

			child->areanum        = chloc->areanum;
			child->numParentLinks = AAS_RT_NumParentLinks(chloc);

			child->startParentLinks = parentLinkCount;

			parentLinkCount += child->numParentLinks;
		}

		// parents
		rt->numParents = num_parents;
		rt->parents    = (aas_rt_parent_t *) AAS_RT_GetClearedMemory(rt->numParents * sizeof(aas_rt_parent_t));
		parent         = rt->parents;
		for (i = 0; i < num_parents; i++, parent++)
		{
			apar = area_parents[i];

			parent->areanum           = apar->areanum;
			parent->numParentChildren = apar->numchildren;
			parent->numVisibleParents = apar->numVisibleParents;

			parent->startParentChildren = parentChildrenCount;
			parent->startVisibleParents = visibleParentsCount;

			parentChildrenCount += parent->numParentChildren;
			visibleParentsCount += parent->numVisibleParents;
		}

		// parentChildren
		rt->numParentChildren = parentChildrenCount;
		rt->parentChildren    = (unsigned short int *) AAS_RT_GetClearedMemory(parentChildrenCount * sizeof(unsigned short int));
		psi                   = rt->parentChildren;
		for (i = 0; i < num_parents; i++)
		{
			apar = area_parents[i];
			for (j = 0; j < apar->numchildren; j++, psi++)
			{
				*psi = apar->children[j];
			}
		}

		// visibleParents
		rt->numVisibleParents = visibleParentsCount;
		rt->visibleParents    = (unsigned short int *) AAS_RT_GetClearedMemory(rt->numVisibleParents * sizeof(unsigned short int));
		psi                   = rt->visibleParents;
		for (i = 0; i < num_parents; i++)
		{
			apar = area_parents[i];
			for (j = 0; j < apar->numVisibleParents; j++, psi++)
			{
				*psi = apar->visibleParents[j];
			}
		}

		// parentLinks
		rt->numParentLinks = parentLinkCount;
		rt->parentLinks    = (aas_rt_parent_link_t *) AAS_RT_GetClearedMemory(parentLinkCount * sizeof(aas_rt_parent_link_t));
		plink              = rt->parentLinks;
		for (i = 0; i < childcount; i++)
		{
			chloc = area_childlocaldata[i];
			for (oplink = chloc->parentlink; oplink; plink++, oplink = oplink->next)
			{
				plink->childIndex = oplink->childindex;
				plink->parent     = oplink->parent;
			}
		}

	}
	// ................................................

	// write the newly created table
	AAS_RT_WriteRouteTable();


	botimport.Print(PRT_MESSAGE, "Child Areas: %i\nTotal Parents: %i\nAverage VisAreas: %i\n", (int)childcount, num_parents, (int)(childcount / num_parents));
	botimport.Print(PRT_MESSAGE, "NoRoute Ratio: %i%%\n", (int)((100.0 * noroutecount) / (1.0 * childcount * childcount)));

	memoryend = memorycount;

	// clear allocated memory

// causes crashes in route-caching
//#ifdef USE_ROUTECACHE
//	AAS_FreeRoutingCaches();
//#endif

	for (i = 0; i < childcount; i++)
	{
		AAS_RT_FreeMemory(area_localinfos[i]);
#ifdef CHECK_TRAVEL_TIMES
		AAS_RT_FreeMemory(filteredroutetable[i]);
#endif
	}

	{
		aas_parent_link_t *next, *trav;

		// kill the client areas
		for (i = 0; i < childcount; i++)
		{
			// kill the parent links
			next = area_childlocaldata[i]->parentlink;
			// TTimo gcc: suggests () around assignment used as truth value
			while ((trav = next))
			{
				next = next->next;

				AAS_RT_FreeMemory(trav->routeindexes);
				AAS_RT_FreeMemory(trav);

			}

			AAS_RT_FreeMemory(area_childlocaldata[i]->localroutes);
			AAS_RT_FreeMemory(area_childlocaldata[i]->parentroutes);
			AAS_RT_FreeMemory(area_childlocaldata[i]);
		}

		// kill the parents
		for (i = 0; i < num_parents; i++)
		{
			AAS_RT_FreeMemory(area_parents[i]->children);
			AAS_RT_FreeMemory(area_parents[i]->visibleParents);
			AAS_RT_FreeMemory(area_parents[i]);
		}
	}

	AAS_RT_FreeMemory(area_localinfos);
	AAS_RT_FreeMemory(area_childlocaldata);
	AAS_RT_FreeMemory(filtered_areas);
	AAS_RT_FreeMemory(rev_filtered_areas);
#ifdef CHECK_TRAVEL_TIMES
	AAS_RT_FreeMemory(filteredroutetable);
#endif

	// check how much memory we've used, and intend to keep
	AAS_RT_PrintMemoryUsage();

	botimport.Print(PRT_MESSAGE, "Route-Table Permanent Memory Usage: %i\n", memorycount);
	botimport.Print(PRT_MESSAGE, "Route-Table Calculation Usage: %i\n", memoryend + cachememory);
	botimport.Print(PRT_MESSAGE, "---------------------------------\n");
}