mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
435
Code/wwphys/pathmgr.cpp
Normal file
435
Code/wwphys/pathmgr.cpp
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
** 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 ;
|
||||
}
|
||||
Reference in New Issue
Block a user