Files
GTASource/game/Peds/AssistedMovementStore.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

339 lines
9.8 KiB
C++

#ifndef ASSISTEDMOVEMENTSTORE_H
#define ASSISTEDMOVEMENTSTORE_H
//Rage headers.
#include "Script/thread.h"
#include "Vector/Vector3.h"
#include "fwvehicleai/pathfindtypes.h"
#include "system/memops.h"
class CEntity;
class CPed;
class CObject;
//****************************************************************************
// CAssistedMovementRoute
// A route which the player will snap to when moving through the world.
// This is intended to help guide the player through awkward areas - such
// as across narrow walkways, stairwells, etc.
// We might want to extend this class to contain more info about each point,
// such as a snap-strength, or area of effect.
class CAssistedMovementRoute
{
friend class CAssistedMovementRouteStore;
friend class CPedDebugVisualiserMenu;
public:
enum eRouteFlags
{
RF_HasBeenPostProcessed = 0x01,
RF_IsActiveWhenStrafing = 0x02,
RF_DisableInForwardsDirection = 0x04,
RF_DisableInReverseDirection = 0x08
};
enum eRoutePointFlags // Be sure to keep these in sync with script enum in "commands_player.sch"
{
RPF_ReduceSpeedForCorners = 0x01,
RPF_IsUnderwater = 0x02
};
struct TRoutePoint
{
Vector3 m_vPos; // also contains 'm_fWidth' in W component
Vector3 m_vTangent; // also contains 'm_fTension' in W component
};
CAssistedMovementRoute();
inline ~CAssistedMovementRoute() { }
enum eRouteType
{
ROUTETYPE_NONE = 0,
ROUTETYPE_MAP = 1,
ROUTETYPE_DOOR = 2,
ROUTETYPE_SCRIPT = 4,
ROUTETYPE_WAYPOINTRECORDING = 8,
ROUTETYPE_DEBUG = 16,
ROUTEYYPE_ANY = ROUTETYPE_MAP + ROUTETYPE_DOOR + ROUTETYPE_SCRIPT + ROUTETYPE_WAYPOINTRECORDING + ROUTETYPE_DEBUG
};
enum
{
MAX_NUM_ROUTE_ELEMENTS = 64
};
void Init();
inline void Clear() { Init(); }
inline const Vector3 & GetMin() const { return m_vMin; }
inline const Vector3 & GetMax() const { return m_vMax; }
inline s32 GetSize() const { return m_iSize; }
inline float GetLength() const { return m_fLength; }
inline u32 GetFlags() const { return m_iFlags; }
inline void SetFlags(const u32 f) { m_iFlags = f; }
Vector3 GetPathBoundaryPoint(const s32 p, const float fPathWidth);
bool GetClosestPos(const Vector3 & vSrcPos, int & iOutRouteSegment, float & fOutRouteSegmentProgress, Vector3 & vOutPosOnRoute, Vector3 & vOutRouteNormal, Vector3 & vOutTangent, u32 & iOutFlags) const;
float GetClosestPos(const Vector3 & vSrcPos, Vector3 * vOutPosOnRoute=NULL, Vector3 * vOutRouteNormal=NULL, Vector3 * vOutTangent=NULL, float * fOutTension=NULL, u32 * iOutFlags=0) const;
bool GetAtDistAlong(float fInputDist, Vector3 * vOutPosOnRoute=NULL, Vector3 * vOutRouteNormal=NULL, Vector3 * vOutTangent=NULL, float * fOutTension=NULL) const;
inline u32 GetPathStreetNameHash() const { return m_iPathStreetNameHash; }
inline void SetPathStreetNameHash(const u32 i) { m_iPathStreetNameHash = i; }
inline void SetRouteType(const s32 r) { m_iRouteType = r; }
inline s32 GetRouteType() const { return m_iRouteType; }
// Calculate total length, tangents & min/max
void PostProcessRoute();
inline void CopyFrom(const CAssistedMovementRoute & src)
{
sysMemCpy(this, &src, sizeof(CAssistedMovementRoute));
}
inline void AddPoint(const Vector3 & vPos, const float fWidth=ms_fDefaultPathWidth, const u32 iFlags=0, const float fTension=ms_fDefaultPathTension)
{
Assert(m_iSize < MAX_NUM_ROUTE_ELEMENTS);
m_Points[m_iSize].m_vPos = vPos;
m_Points[m_iSize].m_vPos.w = fWidth;
m_Points[m_iSize].m_vTangent = VEC3_ZERO;
m_Points[m_iSize].m_vTangent.w = fTension;
m_PointFlags[m_iSize] = iFlags;
m_iSize++;
}
// Element access functions
inline const Vector3 & GetPoint(const s32 p) const
{
Assert(p>=0 && p<MAX_NUM_ROUTE_ELEMENTS);
return m_Points[p].m_vPos;
}
inline float GetPointWidth(const s32 p) const
{
Assert(p>=0 && p<MAX_NUM_ROUTE_ELEMENTS);
return m_Points[p].m_vPos.w;
}
inline u32 GetPointFlags(const s32 p) const
{
Assert(p>=0 && p<MAX_NUM_ROUTE_ELEMENTS);
return m_PointFlags[p];
}
inline float GetPointTension(const s32 p) const
{
Assert(p>=0 && p<MAX_NUM_ROUTE_ELEMENTS);
return m_Points[p].m_vTangent.w;
}
inline const Vector3 & GetPointTangent(const s32 p) const
{
Assert(p>=0 && p<MAX_NUM_ROUTE_ELEMENTS);
return m_Points[p].m_vTangent;
}
static const float ms_fDefaultPathWidth;
static const float ms_fDefaultPathTension;
static const float ms_fTangentLerpMaxDist;
private:
// The min/max of all the points
Vector3 m_vMin;
Vector3 m_vMax;
TRoutePoint m_Points[MAX_NUM_ROUTE_ELEMENTS];
u32 m_PointFlags[MAX_NUM_ROUTE_ELEMENTS]; // moved out of TRoutePoint so that memory may be packed better
u32 m_iFlags;
s32 m_iSize;
float m_fLength;
// The unique index of this route within the CPathFind system (see "VehicleAI/pathfind.h")
u32 m_iPathStreetNameHash;
// Used to distinguish between routes which came from the map, were auto-generated from doors, or came from a script.
s32 m_iRouteType;
};
class CAssistedMovementToggles
{
public:
enum { MAX_NUM_TOGGLES = 32 };
CAssistedMovementToggles();
void Init();
bool TurnOnThisRoute(const u32 iRouteNameHash, const scrThreadId iScriptThreadId);
bool TurnOffThisRoute(const u32 iRouteNameHash, const scrThreadId iScriptThreadId);
inline bool GetHasChanged() const { return m_bHasChanged; }
inline void SetHasChanged(const bool b) { m_bHasChanged = b; }
bool IsThisRouteRequested(const u32 iRouteNameHash, CPathNode * pPathNode=NULL) const;
void ResetAll(const scrThreadId iThreadId);
private:
class CToggle
{
public:
// Which script does this toggle belong to
scrThreadId m_iScriptThreadId;
// Hashname of the route
u32 m_iRouteNameHash;
CToggle() { Reset(); }
void Reset()
{
m_iRouteNameHash = 0;
m_iScriptThreadId = THREAD_INVALID;
}
};
bool m_bHasChanged;
CToggle m_Toggles[MAX_NUM_TOGGLES];
};
//**************************************************************
// CAssistedMovementRouteStore
// A storage class for the routes.
class CAssistedMovementRouteStore
{
friend class CPedDebugVisualiserMenu;
public:
CAssistedMovementRouteStore() { }
~CAssistedMovementRouteStore() { }
enum
{
MAX_MAP_ROUTES = 72,
MAX_SCRIPTED_ROUTES = 8,
MAX_WAYPOINT_ROUTES = 8,
MAX_ROUTES = MAX_MAP_ROUTES + MAX_SCRIPTED_ROUTES + MAX_WAYPOINT_ROUTES,
FIRST_MAP_ROUTE = 0,
FIRST_SCRIPTED_ROUTE = FIRST_MAP_ROUTE + MAX_MAP_ROUTES,
FIRST_WAYPOINT_ROUTE = FIRST_SCRIPTED_ROUTE + MAX_SCRIPTED_ROUTES
};
static void Init(unsigned initMode);
static void Shutdown(unsigned shutdownMode);
static CAssistedMovementToggles & GetRouteToggles() { return m_RouteToggles; }
static inline CAssistedMovementRoute * GetRoute(const int r)
{
Assert(r >=0 && r < MAX_ROUTES);
return &ms_RouteStore[r];
}
static inline CAssistedMovementRoute * GetRouteByNameHash(const u32 iHash)
{
Assert(iHash);
if(!iHash)
return NULL;
for(int i=0; i<MAX_ROUTES; i++)
{
if( ms_RouteStore[i].GetPathStreetNameHash()==iHash )
{
return &ms_RouteStore[i];
}
}
return NULL;
}
static inline CAssistedMovementRoute * GetEmptyRoute(const bool bMapPool, const bool bScriptPool, const bool bWaypointRecordingPool)
{
Assert(!(bMapPool&&bScriptPool));
Assert(!(bMapPool&&bWaypointRecordingPool));
Assert(!(bScriptPool&&bWaypointRecordingPool));
int r;
if(bMapPool)
{
for(r=FIRST_MAP_ROUTE; r<MAX_MAP_ROUTES; r++)
if(ms_RouteStore[r].m_iSize==0 && ms_RouteStore[r].m_iPathStreetNameHash==0)
return &ms_RouteStore[r];
}
else if(bScriptPool)
{
for(r=FIRST_SCRIPTED_ROUTE; r<FIRST_SCRIPTED_ROUTE+MAX_SCRIPTED_ROUTES; r++)
if(ms_RouteStore[r].m_iSize==0 && ms_RouteStore[r].m_iPathStreetNameHash==0)
return &ms_RouteStore[r];
}
else if(bWaypointRecordingPool)
{
for(r=FIRST_WAYPOINT_ROUTE; r<FIRST_WAYPOINT_ROUTE+MAX_WAYPOINT_ROUTES; r++)
if(ms_RouteStore[r].m_iSize==0 && ms_RouteStore[r].m_iPathStreetNameHash==0)
return &ms_RouteStore[r];
}
return NULL;
}
static inline void ClearAll(const s32 iTypeMask)
{
for(int r=0; r<MAX_ROUTES; r++)
{
if(ms_RouteStore[r].GetRouteType() & iTypeMask)
ms_RouteStore[r].Clear();
}
}
static void Process(CPed * pPed, const bool bForceUpdate);
static void MaybeAddRouteForDoor(CEntity * pEntity);
static void MaybeRemoveRouteForDoor(CEntity * pEntity);
static inline int GetScriptRouteEditIndex() { return ms_iScriptRouteEditIndex; }
static inline void SetScriptRouteEditIndex(const int i) { ms_iScriptRouteEditIndex = i; }
static u32 CalcDoorHash(CObject * pDoor);
static u32 CalcScriptedRouteHash(const int iRouteIndex);
static void SetStreamingLoadDistance(float f) { ms_fStreamingLoadDistance = f; }
static bool ShouldProcessNode(CPathNode * pNode);
#if !__FINAL
static void Debug();
#if __BANK
static void RescanNow();
#endif
#endif
private:
static CAssistedMovementRoute * ms_RouteStore;
//***************************************************************************
// The assisted movement routes are stored in the CPathFind node network,
// which handles their streaming, etc. Every so often this store is updated
// from the node system - far away routes are cleared out, and new ones are
// added. We must also make sure that existing routes are updates because
// they may not always be all loaded in if they straddle a region boundary.
static void UpdateRoutesFromNodesSystem(const Vector3 & vOrigin);
static void UpdateRoutesFromWaypointRecordings(const Vector3 & vOrigin);
static bool IsPermanentRoute(const CPathNode * pNode);
static Vector3 m_vLastOrigin;
// The index of the script route being created via script commands - or '-1' if none.
static int ms_iScriptRouteEditIndex;
static float ms_fStreamingLoadDistance;
static float ms_fStreamingUpdatePosDeltaSqr;
static const float ms_fDefaultStreamingLoadDistance;
static bank_float ms_fDistOutFromDoor;
static bank_bool ms_bAutoGenerateRoutesInDoorways;
static CAssistedMovementToggles m_RouteToggles;
};
#endif // ASSISTEDMOVEMENTSTORE_H