This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwphys/pathmgr.cpp

435 lines
11 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWPhys *
* *
* $Archive:: /Commando/Code/wwphys/pathmgr.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 12/10/01 12:40p $*
* *
* $Revision:: 8 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "pathmgr.h"
#include "pathsolve.h"
#include "chunkio.h"
#include "win.h"
#include "wwmemlog.h"
#include "systimer.h"
////////////////////////////////////////////////////////////////
// Save/Load constants
////////////////////////////////////////////////////////////////
enum
{
CHUNKID_PATH_SOLVE_OBJECT = 0x11070935,
};
/////////////////////////////////////////////////////////////////////////
// Static member initialization
/////////////////////////////////////////////////////////////////////////
DynamicVectorClass<PathSolveClass *> PathMgrClass::AvailablePathList;
DynamicVectorClass<PathSolveClass *> PathMgrClass::UsedPathList;
PathSolveClass * PathMgrClass::ActivePath = NULL;
__int64 PathMgrClass::TicksPerMilliSec = 0;
/////////////////////////////////////////////////////////////////////////
// Constants
/////////////////////////////////////////////////////////////////////////
static const int DEFAULT_OBJ_COUNT = 15;
/////////////////////////////////////////////////////////////////////////
//
// Initialize
//
/////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Initialize (void)
{
Allocate_Objects ();
//
// Determine what the resolution of our timer is
//
if (TicksPerMilliSec == 0) {
::QueryPerformanceFrequency ((LARGE_INTEGER *)&TicksPerMilliSec);
TicksPerMilliSec /= 1000;
}
return ;
}
/////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
/////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Shutdown (void)
{
Free_Objects ();
return ;
}
/////////////////////////////////////////////////////////////////////////
//
// Free_Objects
//
/////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Free_Objects (void)
{
if (ActivePath != NULL) {
ActivePath->Unlink_Pathfind_Hooks ();
ActivePath = NULL;
}
//
// Free the list of available objects
//
for (int index = 0; index < AvailablePathList.Count (); index ++) {
PathSolveClass *path = AvailablePathList[index];
REF_PTR_RELEASE (path);
}
//
// Free the list of used objects
//
for (index = 0; index < UsedPathList.Count (); index ++) {
PathSolveClass *path = UsedPathList[index];
REF_PTR_RELEASE (path);
}
//
// Reset the lists
//
AvailablePathList.Delete_All ();
UsedPathList.Delete_All ();
return ;
}
/////////////////////////////////////////////////////////////////////////
//
// Allocate_Objects
//
/////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Allocate_Objects (void)
{
Free_Objects ();
//
// Allocate a default number of path objects
//
for (int index = 0; index < DEFAULT_OBJ_COUNT; index ++) {
AvailablePathList.Add (new PathSolveClass);
}
return ;
}
/////////////////////////////////////////////////////////////////////////
//
// Request_Path_Object
//
/////////////////////////////////////////////////////////////////////////
PathSolveClass *
PathMgrClass::Request_Path_Object (void)
{
WWMEMLOG(MEM_PATHFIND);
PathSolveClass *path_object = NULL;
int avail_count = AvailablePathList.Count ();
if (avail_count > 0) {
//
// Return the path object from the end of the list. Note: this is a
// little more efficient when working with DynamicVectorClass objects.
//
path_object = AvailablePathList[avail_count - 1];
AvailablePathList.Delete (avail_count - 1);
} else {
//
// Allocate a new object (note: we should get this object back later so
// it will be added to our internal list at that time).
//
path_object = new PathSolveClass;
}
//
// Add this object to the used path list
//
if (path_object != NULL) {
UsedPathList.Add (path_object);
}
//
// Return the path object to the caller
//
return path_object;
}
/////////////////////////////////////////////////////////////////////////
//
// Return_Path_Object
//
/////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Return_Path_Object (PathSolveClass *path)
{
WWASSERT (path != NULL);
if (path != NULL) {
//
// Make sure the object doesn't already exist in our list
//
int index = AvailablePathList.ID (path);
WWASSERT (index == -1);
if (index == -1) {
//
// Find out where the object exists in the used list
//
int used_index = UsedPathList.ID (path);
WWASSERT (used_index != -1);
if (used_index != -1) {
//
// Reset our active path pointer (if necessary)
//
if (path == ActivePath) {
ActivePath->Unlink_Pathfind_Hooks ();
ActivePath = NULL;
}
//
// Remove the object from the used list
//
UsedPathList.Delete (used_index);
//
// Add the path object to our list (its assumed we
// will inherit the ref-count from the caller)
//
path->Reset_Lists ();
AvailablePathList.Add (path);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Save
//
////////////////////////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Save (ChunkSaveClass &csave)
{
//
// Save each of the path objects
//
for (int index = 0; index < UsedPathList.Count (); index ++) {
PathSolveClass *path = UsedPathList[index];
csave.Begin_Chunk (CHUNKID_PATH_SOLVE_OBJECT);
path->Save (csave);
csave.End_Chunk ();
}
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Load
//
////////////////////////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Load (ChunkLoadClass &cload)
{
Free_Objects ();
while (cload.Open_Chunk ()) {
switch (cload.Cur_Chunk_ID ()) {
case CHUNKID_PATH_SOLVE_OBJECT:
{
//
// Allocate the path object, load its state, and add it to our list
//
PathSolveClass *path_object = new PathSolveClass;
path_object->Load (cload);
UsedPathList.Add (path_object);
}
break;
}
cload.Close_Chunk ();
}
return ;
}
///////////////////////////////////////////////////////////////////////////
//
// Get_Time
//
///////////////////////////////////////////////////////////////////////////
static inline __int64
Get_Time (void)
{
__int64 curr_time = 0;
::QueryPerformanceCounter ((LARGE_INTEGER *)&curr_time);
return curr_time;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Resolve_Paths
//
////////////////////////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Resolve_Paths (const Vector3 &camera_pos, uint32 milliseconds)
{
__int64 start_time = Get_Time ();
__int64 end_time = start_time + (((__int64)milliseconds) * TicksPerMilliSec);
WWMEMLOG(MEM_PATHFIND);
//
// Keep processing path's until we've used up our timeslice
//
do
{
//
// Find a path that needs to be solved
//
if (ActivePath == NULL) {
Activate_New_Priority_Path (camera_pos);
}
//
// Do we have any paths to solve?
//
if (ActivePath != NULL) {
//
// Let this path think for (up to) the remainder of our timeslice
//
uint32 time_slice = uint32((end_time - Get_Time ()) / TicksPerMilliSec);
PathSolveClass::STATE_DESC result = ActivePath->Timestep (time_slice);
//
// If the path finished solving, then reset the active path
//
if (result != PathSolveClass::THINKING) {
ActivePath->Unlink_Pathfind_Hooks ();
ActivePath = NULL;
}
} else {
break;
}
} while (Get_Time () < end_time);
return ;
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// Activate_New_Priority_Path
//
////////////////////////////////////////////////////////////////////////////////////////////
void
PathMgrClass::Activate_New_Priority_Path (const Vector3 &camera_pos)
{
ActivePath = NULL;
float best_priority = 0;
//
// Find the highest priority path that needs solving
//
for (int index = 0; index < UsedPathList.Count (); index ++) {
PathSolveClass *path = UsedPathList[index];
//
// Don't bother with paths that are already solved
//
if (path->Get_State () == PathSolveClass::THINKING) {
//
// Get the different priority factors for this path
//
float dist = (path->Get_Start_Pos () - camera_pos).Length ();
float pos_priority = 1.0F - WWMath::Clamp (dist / 20.0F, 0.0F, 1.0F);
float path_priority = WWMath::Clamp (path->Get_Priority (), 0.0F, 1.0F);
float time_priority = (TIMEGETTIME () - path->Get_Birth_Time ()) / 5000.0F;
//
// Calculate a final priority based on these factors
//
float priority = (path_priority * 0.5F) + (pos_priority * 0.5F) + time_priority;
//
// If this is best path so far, then choose it
//
if (priority > best_priority) {
best_priority = priority ;
ActivePath = path;
}
}
}
//
// Kick off the pathfind
//
if (ActivePath != NULL) {
ActivePath->Process_Initial_Sector ();
}
return ;
}