Files
GTASource/game/control/WaypointRecording.cpp
T
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1979 lines
71 KiB
C++

#include "WaypointRecording.h"
//game includes
#include "control\gamelogic.h"
#include "fwsys\fileExts.h"
#include "camera/CamInterface.h"
#include "camera/debug/DebugDirector.h"
#include "camera/helpers/Frame.h"
#include "core\game.h"
#include "modelinfo/PedModelInfo.h"
#include "Peds\AssistedMovement.h"
#include "Peds\ped.h"
#include "Peds\PedFactory.h"
#include "peds/Ped.h"
#include "Peds\PedMoveBlend\PedMoveBlendInWater.h"
#include "Peds\PedMoveBlend\PedMoveBlendOnSkis.h"
#include "Peds\PedDebugVisualiser.h"
#include "Peds\PedIntelligence.h"
#include "physics/physics.h"
#include "Scene\World\GameWorld.h"
#include "streaming/streaming.h"
#include "Task\Motion\Locomotion\TaskMotionPed.h"
#include "Task\Movement\TaskGoto.h"
#include "Task\Movement\TaskFollowWaypointRecording.h"
#include "Task\Movement\Jumping\TaskJump.h"
#include "Task\General\TaskBasic.h"
#include "vehicleAi\task\TaskVehicleFollowRecording.h"
#include "debug/DebugScene.h"
#include "Task/Vehicle/TaskCar.h"
//rage includes
#include "math\angmath.h"
AI_OPTIMISATIONS()
#if __BANK
bank_float CWaypointRecording::ms_fMBRDeltaForNewWaypointOnSkis = 0.45f;
bank_float CWaypointRecording::ms_fMBRDeltaForNewWaypointOnFoot = 0.25f;
bank_float CWaypointRecording::ms_fMinWaypointSpacing = 1.0f;
bank_float CWaypointRecording::ms_fMaxWaypointSpacingOnSkis = 10.0f;
bank_float CWaypointRecording::ms_fMaxWaypointSpacingOnFoot = 2.0f;
bank_float CWaypointRecording::ms_fMaxPlaneDistOnSkis = 1.0f;
bank_float CWaypointRecording::ms_fMaxPlaneDistOnFoot = 0.5f;
bank_float CWaypointRecording::ms_fMBRDeltaForNewWaypointInVehicle = 1.0f;
bank_float CWaypointRecording::ms_fMaxWaypointSpacingInVehicle = 10.0f;
bank_float CWaypointRecording::ms_fMaxPlaneDistInVehicle = 1.0f;
bool CWaypointRecording::ms_bDebugDraw = false;
bool CWaypointRecording::ms_bLoopRoutePlayback = true;
bool CWaypointRecording::ms_bUseAISlowdown = false;
bool CWaypointRecording::ms_bDisplayStore = false;
int CWaypointRecording::ms_iDebugStoreIndex = 0;
char CWaypointRecording::ms_TestRouteName[128] = { 0 };
float CWaypointRecording::ms_fAssistedMovementPathWidth = CAssistedMovementRoute::ms_fDefaultPathWidth;
float CWaypointRecording::ms_fAssistedMovementPathTension = CAssistedMovementRoute::ms_fDefaultPathTension;
CPed * CWaypointRecording::ms_pPed = NULL;
::CWaypointRecordingRoute CWaypointRecording::ms_RecordingRoute;
bool CWaypointRecording::ms_bRecording = false;
bool CWaypointRecording::ms_bRecordingVehicle = false;
bool CWaypointRecording::ms_bWasFlipped = false;
bool CWaypointRecording::ms_bUnderwaterLastFrame = false;
bool CWaypointRecording::ms_bWaypointEditing = false;
char CWaypointRecording::m_LoadedRouteName[256] = { 0 };
int CWaypointRecording::m_iLoadedRouteNumWaypoints = 0;
float fOverrideMBR = MOVEBLENDRATIO_WALK;
bool bUseRunAndGun = false;
CWaypointRecording::TEditingControls CWaypointRecording::ms_EditingControls;
#endif
CWaypointRecordingStreamingInterface CWaypointRecording::m_StreamingInterface;
CLoadedWaypointRecording CWaypointRecording::ms_LoadedRecordings[ms_iMaxNumLoaded];
CWaypointRecording::TStreamingInfo* CWaypointRecording::m_StreamingInfo = NULL;
#if __BANK
void StartRecordingOnFocusPed()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CWaypointRecording::ms_bDebugDraw = true;
CWaypointRecording::ClearRoute();
CWaypointRecording::StartRecording(pFocus);
}
}
void StartRecordingOnPlayerPed()
{
CWaypointRecording::ms_bDebugDraw = true;
CWaypointRecording::ClearRoute();
CWaypointRecording::StartRecording(FindPlayerPed());
}
void StartRecordingOnPlayerVehicle()
{
CWaypointRecording::ms_bDebugDraw = true;
CWaypointRecording::ClearRoute();
CWaypointRecording::StartRecording(FindPlayerPed(), true);
}
void StopRecording()
{
if(CWaypointRecording::GetIsRecording())
{
CWaypointRecording::StopRecording();
}
}
void StartPlaybackOnFocusPed()
{
if(!CWaypointRecording::GetIsRecording())
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CWaypointRecording::StartPlayback(pFocus);
}
}
}
void StartPlaybackOnPlayerPed()
{
if(!CWaypointRecording::GetIsRecording())
{
CWaypointRecording::StartPlayback(FindPlayerPed());
}
}
void StartPlaybackOnPlayerVehicle()
{
if(!CWaypointRecording::GetIsRecording())
{
CWaypointRecording::StartPlayback(FindPlayerPed(), true);
}
}
void StartPlaybackOnFocusPedVehicle()
{
if(!CWaypointRecording::GetIsRecording())
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CWaypointRecording::StartPlayback(pFocus, true);
}
}
}
void StopPlayback()
{
if(!CWaypointRecording::GetIsRecording())
{
CWaypointRecording::StopPlayback();
}
}
void ClearRoute()
{
if(!CWaypointRecording::GetIsRecording())
{
CWaypointRecording::ClearRoute();
}
}
void SaveRoute()
{
Assertf(!CWaypointRecording::GetIsRecording(), "You need to stop recording first!");
Assertf(CWaypointRecording::GetRecordingRoute()->GetSize(), "Route has no points!");
if(!CWaypointRecording::GetRecordingRoute()->SanityCheck())
{
Assertf(false, "ERROR - the route has issues.. It cannot be saved until these are fixed.");
return;
}
char filename[512];
BANKMGR.OpenFile(filename, 512, "*.iwr", true, "Save waypoint file");
{
if(!CWaypointRecording::CheckWaypointRecordingName(filename))
{
Assertf(false, "Bad filename!");
return;
}
fiStream * pFile = fiStream::Create(filename);
Assertf(pFile, "Couldn't open file \"%s\" for writing.", filename);
if(pFile)
{
CWaypointRecording::GetRecordingRoute()->Save(pFile);
pFile->Flush();
pFile->Close();
}
}
}
void LoadRoute()
{
Assertf(!CWaypointRecording::GetIsRecording(), "You need to stop recording first!");
char filename[512];
BANKMGR.OpenFile(filename, 512, "*.iwr", false, "Load waypoint file");
{
if(!CWaypointRecording::CheckWaypointRecordingName(filename))
{
Assertf(false, "Bad filename!");
return;
}
fiStream * pFile = fiStream::Open(filename);
Assertf(pFile, "Couldn't open file \"%s\" for reading.", filename);
if(pFile)
{
CWaypointRecording::GetRecordingRoute()->Clear();
CWaypointRecording::GetRecordingRoute()->Load(pFile, CWaypointRecording::GetRecordingRoute()->GetWaypointsBuffer() );
pFile->Flush();
pFile->Close();
strcpy(CWaypointRecording::m_LoadedRouteName, filename);
CWaypointRecording::m_iLoadedRouteNumWaypoints = CWaypointRecording::GetRecordingRoute()->GetSize();
CWaypointRecording::ms_EditingControls.m_iSelectedWaypoint = 0;
}
}
}
void TestStreamRoute()
{
CWaypointRecording::RequestRecording(CWaypointRecording::ms_TestRouteName, THREAD_INVALID);
}
void TestRemoveRoute()
{
CWaypointRecording::RemoveRecording(CWaypointRecording::ms_TestRouteName, THREAD_INVALID);
}
void TestStreamingLoadAllRequested()
{
CStreaming::LoadAllRequestedObjects();
}
void WarpPlayerToRouteStart()
{
::CWaypointRecordingRoute * pRoute = CWaypointRecording::GetRecordingBySlotIndex(CWaypointRecording::ms_iDebugStoreIndex);
if(pRoute && pRoute->GetSize() >= 2)
{
const ::CWaypointRecordingRoute::RouteData & wpt1 = pRoute->GetWaypoint(0);
const ::CWaypointRecordingRoute::RouteData & wpt2 = pRoute->GetWaypoint(1);
const float fHdg = fwAngle::GetRadianAngleBetweenPoints(wpt2.GetPosition().x, wpt2.GetPosition().y, wpt1.GetPosition().x, wpt1.GetPosition().y);
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->Teleport(wpt1.GetPosition(), fHdg);
}
}
}
void TestPlayStreamedRecording(CPed * pPed, int iSlot)
{
if(pPed)
{
::CWaypointRecordingRoute * pRoute = CWaypointRecording::GetRecordingBySlotIndex(iSlot);
if(pRoute && pRoute->GetSize() >= 2)
{
const ::CWaypointRecordingRoute::RouteData & wpt1 = pRoute->GetWaypoint(0);
const ::CWaypointRecordingRoute::RouteData & wpt2 = pRoute->GetWaypoint(1);
const float fHdg = fwAngle::GetRadianAngleBetweenPoints(wpt2.GetPosition().x, wpt2.GetPosition().y, wpt1.GetPosition().x, wpt1.GetPosition().y);
pPed->GetPrimaryMotionTask()->ForceReset();
pPed->Teleport(wpt1.GetPosition(), fHdg);
CTaskFollowWaypointRecording * pFollowTask = rage_new CTaskFollowWaypointRecording(pRoute);
pFollowTask->SetLoopPlayback(CWaypointRecording::ms_bLoopRoutePlayback);
pPed->GetPedIntelligence()->AddTaskAtPriority(pFollowTask, PED_TASK_PRIORITY_PRIMARY);
}
}
}
void TestPlayStreamedRecordingOnFocusPed()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
TestPlayStreamedRecording(pFocus, CWaypointRecording::ms_iDebugStoreIndex);
}
}
void TestPauseFocusPed()
{
static dev_bool bStopBeforeOrientation = true;
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->SetPause(false, bStopBeforeOrientation);
}
}
}
void TestPauseFocusPedAndFacePlayer()
{
static dev_bool bStopBeforeOrientation = true;
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->SetPause(true, bStopBeforeOrientation);
}
}
}
void TestResumeFocusPed()
{
static int iOptionalDelayMs = 3000;
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->SetResume(true, -1, iOptionalDelayMs);
}
}
}
void TestOverrideSpeed()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->SetOverrideMoveBlendRatio(fOverrideMBR, true);
}
}
}
void TestUseDefaultSpeed()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->UseDefaultMoveBlendRatio();
}
}
}
void TestFollowRouteAimingAtPlayer()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus && pFocus != FindPlayerPed())
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->StartAimingAtEntity(FindPlayerPed(), bUseRunAndGun);
}
}
}
void TestStopAimingOrShooting()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus)
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->StopAimingOrShooting();
}
}
}
void TestFollowRouteShootingAtPlayer()
{
CPed * pFocus = CPedDebugVisualiserMenu::GetFocusPed();
if(pFocus && pFocus != FindPlayerPed())
{
CTask * pTask = pFocus->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING);
if(pTask)
{
((CTaskFollowWaypointRecording*)pTask)->StartShootingAtEntity(FindPlayerPed(), bUseRunAndGun);
}
}
}
void ToggleUseAsAssistedMovementRoute()
{
::CWaypointRecordingRoute * pRoute = CWaypointRecording::GetRecordingBySlotIndex(CWaypointRecording::ms_iDebugStoreIndex);
if(pRoute)
{
if(pRoute->GetFlags() & ::CWaypointRecordingRoute::RouteFlag_AssistedMovement)
{
pRoute->SetFlags(pRoute->GetFlags() & ~::CWaypointRecordingRoute::RouteFlag_AssistedMovement);
}
else
{
pRoute->SetFlags(pRoute->GetFlags() | ::CWaypointRecordingRoute::RouteFlag_AssistedMovement);
}
CLoadedWaypointRecording * pRecordingInfo = CWaypointRecording::GetLoadedWaypointRecordingInfo(pRoute);
pRecordingInfo->SetAssistedMovementPathWidth(CWaypointRecording::ms_fAssistedMovementPathWidth);
pRecordingInfo->SetAssistedMovementPathTension(CWaypointRecording::ms_fAssistedMovementPathTension * 2.0f);
CAssistedMovementRouteStore::Process(FindPlayerPed(), true);
}
}
#define NUM_SKI_PEDS 5
void SpawnSkiersForStreamedRecordings()
{
const char * skiPeds[NUM_SKI_PEDS] =
{
"A_M_M_SkiVill_04",
"A_M_M_SkiVill_06",
"A_M_M_SkiVill_07",
"A_M_M_SkiVill_08",
"A_M_M_SkiVill_09"
};
for(int s=0; s<CWaypointRecording::ms_iMaxNumLoaded; s++)
{
::CWaypointRecordingRoute * pRoute = CWaypointRecording::GetRecordingBySlotIndex(s);
if(pRoute && pRoute->GetSize() >= 2)
{
const ::CWaypointRecordingRoute::RouteData & wpt1 = pRoute->GetWaypoint(0);
// Create a ped
const char * pSkiPed = skiPeds[ fwRandom::GetRandomNumberInRange(0, NUM_SKI_PEDS) ];
fwModelId modelId = CModelInfo::GetModelIdFromName(pSkiPed);
if(modelId.IsValid())
{
// ensure that the model is loaded and ready for drawing for this ped
if (!CModelInfo::HaveAssetsLoaded(modelId))
{
CModelInfo::RequestAssets(modelId, STRFLAG_FORCE_LOAD|STRFLAG_PRIORITY_LOAD);
CStreaming::LoadAllRequestedObjects(true);
}
Matrix34 mPed;
mPed.Identity();
mPed.MakeTranslate(wpt1.GetPosition());
mPed.RotateFullZ(wpt1.GetHeading());
const CControlledByInfo pedControl(false, false);
const bool bMissionChar = true;
CPed * pPed = CPedFactory::GetFactory()->CreatePed(pedControl, modelId, &mPed, true, true, bMissionChar);
pPed->PopTypeSet(POPTYPE_MISSION);
pPed->SetDontLoadCollision(false);
pPed->SetDefaultDecisionMaker();
pPed->GetPedIntelligence()->SetDefaultRelationshipGroup();
CGameWorld::Add(pPed, CGameWorld::OUTSIDE );
pPed->SetPedConfigFlag( CPED_CONFIG_FLAG_IsSkiing, true );
TestPlayStreamedRecording(pPed, s);
}
}
}
}
void TestGetWaypointDistanceFromStart()
{
static dev_s32 iIndex = 10;
static float fDistance = 0.0f;
if(CWaypointRecording::GetRecordingRoute()->GetSize() >= iIndex)
{
fDistance = CWaypointRecording::GetRecordingRoute()->GetWaypointDistanceFromStart(iIndex);
Displayf("Distance : %.2f\n", fDistance);
}
}
void TestGetPlayerDistanceAlongRoute()
{
CWaypointRecordingRoute * pRoute = CWaypointRecording::GetRecording("FBI1");
if(pRoute && FindPlayerPed())
{
int i = pRoute->GetClosestWaypointIndex(VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition()));
if(i <=0 && i <pRoute->GetSize())
{
float fDistance = CWaypointRecording::GetRecordingRoute()->GetWaypointDistanceFromStart(i);
Displayf("Distance : %.2f\n", fDistance);
}
}
}
#endif // __BANK
//******************************************************************************************
CLoadedWaypointRecording::CLoadedWaypointRecording()
{
Reset();
}
void CLoadedWaypointRecording::Reset()
{
m_iFileNameHashKey = 0;
m_pRecording = NULL;
m_iNumReferences = 0;
m_iScriptID = THREAD_INVALID;
m_fAssistedMovementPathWidth = CAssistedMovementRoute::ms_fDefaultPathWidth;
m_fAssistedMovementPathTension = CAssistedMovementRoute::ms_fDefaultPathTension;
BANK_ONLY( m_Filename[0] = 0; )
}
//******************************************************************************************
static int GetMaxNumRecordingsPerLevel()
{
// Make sure we're never trying to read this before it's been set.
TrapZ(CWaypointRecording::ms_iMaxNumRecordingsPerLevel);
return CWaypointRecording::ms_iMaxNumRecordingsPerLevel;
}
CWaypointRecordingStreamingInterface::CWaypointRecordingStreamingInterface() :
strStreamingModule("wptrec", WAYPOINTRECORDING_FILE_ID, 0, false, false, ::CWaypointRecordingRoute::RORC_VERSION, 1024) { }
int CWaypointRecording::ms_iMaxNumRecordingsPerLevel = 0;
CWaypointRecording::CWaypointRecording()
{
}
CWaypointRecording::~CWaypointRecording()
{
}
void CWaypointRecording::RegisterStreamingModule()
{
// This is a little odd - this is basically the first time we need the size, so we get
// it from the configuration data here. Maybe would be cleaner to add some function that
// gets called after the configuration file has loaded.
if(!ms_iMaxNumRecordingsPerLevel)
{
ms_iMaxNumRecordingsPerLevel = fwConfigManager::GetInstance().GetSizeOfPool(ATSTRINGHASH("wptrec", 0x7809ca42), 256);
m_StreamingInterface.SetCount(ms_iMaxNumRecordingsPerLevel);
}
strStreamingEngine::GetInfo().GetModuleMgr().AddModule(&m_StreamingInterface);
}
void CWaypointRecording::Init(unsigned initMode)
{
USE_MEMBUCKET(MEMBUCKET_GAMEPLAY);
if(initMode == INIT_CORE)
{
Assert(!m_StreamingInfo);
const int cnt = GetMaxNumRecordingsPerLevel();
m_StreamingInfo = rage_new TStreamingInfo[cnt];
for(int i=0; i<cnt; i++)
{
m_StreamingInfo[i].m_iFilenameHashKey = 0;
#if !__FINAL
m_StreamingInfo[i].m_Filename[0] = 0;
#endif
}
#if __BANK
ms_RecordingRoute.AllocForRecording();
#endif
}
}
void CWaypointRecording::Shutdown(unsigned shutdownMode)
{
if(shutdownMode == SHUTDOWN_SESSION)
{
for(int s=0; s<ms_iMaxNumLoaded; s++)
{
if(ms_LoadedRecordings[s].m_pRecording)
{
int iStreamingIndex = GetStreamingIndexForRecording(ms_LoadedRecordings[s].m_iFileNameHashKey);
Assertf(iStreamingIndex != -1, "The requested waypoint route \'%s\' was not found in the .rpf", ms_LoadedRecordings[s].m_Filename);
if(iStreamingIndex==-1)
return;
m_StreamingInterface.ClearRequiredFlag(iStreamingIndex, STRFLAG_MISSION_REQUIRED);
m_StreamingInterface.StreamingRemove(strLocalIndex(iStreamingIndex));
}
ms_LoadedRecordings[s].Reset();
}
}
else if (shutdownMode == SHUTDOWN_WITH_MAP_LOADED)
{
const int cnt = GetMaxNumRecordingsPerLevel();
for(int i=0; i<cnt; i++)
{
m_StreamingInfo[i].m_iFilenameHashKey = 0;
#if !__FINAL
m_StreamingInfo[i].m_Filename[0] = 0;
#endif
}
}
else if(shutdownMode == SHUTDOWN_CORE)
{
Assert(m_StreamingInfo);
delete []m_StreamingInfo;
m_StreamingInfo = NULL;
}
}
#if __BANK
void CWaypointRecording::InitWidgets()
{
bkBank *pBank = CGameLogic::GetGameLogicBank();
if(pBank)
{
pBank->PushGroup("Waypoint Recordings");
pBank->AddButton("Start recording on player ped", StartRecordingOnPlayerPed);
pBank->AddButton("Start recording on player vehicle", StartRecordingOnPlayerVehicle);
pBank->AddButton("Start recording on focus ped", StartRecordingOnFocusPed);
pBank->AddButton("Stop recording", StopRecording);
pBank->AddButton("Start playback on player ped", StartPlaybackOnPlayerPed);
pBank->AddButton("Start playback on focus ped", StartPlaybackOnFocusPed);
pBank->AddButton("Start playback on player vehicle", StartPlaybackOnPlayerVehicle);
pBank->AddButton("Start playback on focus ped vehicle", StartPlaybackOnFocusPedVehicle);
pBank->AddButton("Stop playback", StopPlayback);
pBank->AddButton("Clear route", ClearRoute);
pBank->AddToggle("Display routes", &CWaypointRecording::ms_bDebugDraw);
pBank->AddToggle("Loop playback", &CWaypointRecording::ms_bLoopRoutePlayback);
pBank->AddToggle("Use AI Slowdown", &CWaypointRecording::ms_bUseAISlowdown);
//pBank->AddToggle("Use Bonnet Position", &s_bUseBonnetPositionForVehicleRecordings);
pBank->PushGroup("Recording Params");
//pBank->AddText("Route name: ", ms_RecordingRouteName, 64, false);
pBank->AddButton("Save route", SaveRoute);
pBank->AddButton("Load route", LoadRoute);
pBank->PopGroup();
pBank->PushGroup("Waypoint Editing");
pBank->AddToggle("Enable Waypoint Editing", &CWaypointRecording::ms_bWaypointEditing);
pBank->AddText("Last loaded route name:", &CWaypointRecording::m_LoadedRouteName[0], 255, true);
pBank->AddText("Num waypoints:", &CWaypointRecording::m_iLoadedRouteNumWaypoints, true);
pBank->AddSlider("Current Waypoint: ", &CWaypointRecording::ms_EditingControls.m_iSelectedWaypoint, 0, ::CWaypointRecordingRoute::ms_iMaxNumWaypoints, 1, CWaypointRecording::Edit_OnChangeWaypoint);
pBank->AddButton("Warp player to this waypoint", CWaypointRecording::Edit_OnWarpToWaypoint);
pBank->AddButton("Reposition this waypoint", CWaypointRecording::Edit_RepositionWaypoint);
pBank->AddButton("Insert waypoint after", CWaypointRecording::Edit_InsertWaypoint);
pBank->AddButton("Remove this waypoint", CWaypointRecording::Edit_RemoveWaypoint);
pBank->AddSlider("Modify heading", &CWaypointRecording::ms_EditingControls.m_fWaypointHeading, 0.0, PI*2.0f, 0.1f, CWaypointRecording::Edit_OnModifyHeading);
pBank->AddSlider("Modify MBR", &CWaypointRecording::ms_EditingControls.m_fWaypointMBR, MOVEBLENDRATIO_STILL, MOVEBLENDRATIO_SPRINT, 0.1f, CWaypointRecording::Edit_OnModifyMBR);
pBank->AddSlider("Modify Vehicle Speed", &CWaypointRecording::ms_EditingControls.m_fWaypointMBR, 0.0f, 64.0f, 0.25f, CWaypointRecording::Edit_OnModifyMBR);
pBank->AddSlider("Modify Free Space to Left", &CWaypointRecording::ms_EditingControls.m_fFreeSpaceToLeft, 0.0f, 8.0f, 0.25f, CWaypointRecording::Edit_OnModifyDistLeft);
pBank->AddSlider("Modify Free Space to Right", &CWaypointRecording::ms_EditingControls.m_fFreeSpaceToRight, 0.0f, 8.0f, 0.25f, CWaypointRecording::Edit_OnModifyDistRight);
pBank->AddButton("Apply Free Space to Entire Route", CWaypointRecording::Edit_OnApplyAllDistances);
pBank->AddButton("Snap route to ground", CWaypointRecording::Edit_OnSnapToGround);
pBank->PushGroup("Nudge XYZ");
pBank->AddButton("Increase X", CWaypointRecording::Edit_OnIncreaseX);
pBank->AddButton("Decrease X", CWaypointRecording::Edit_OnDecreaseX);
pBank->AddButton("Increase Y", CWaypointRecording::Edit_OnIncreaseY);
pBank->AddButton("Decrease Y", CWaypointRecording::Edit_OnDecreaseY);
pBank->AddButton("Increase Z", CWaypointRecording::Edit_OnIncreaseZ);
pBank->AddButton("Decrease Z", CWaypointRecording::Edit_OnDecreaseZ);
pBank->PopGroup();
pBank->PushGroup("Translate Route");
pBank->AddSlider("Relative X", &CWaypointRecording::ms_EditingControls.m_vTranslateRoute.x, -8192.0f, 8192.0f, 0.1f);
pBank->AddSlider("Relative Y", &CWaypointRecording::ms_EditingControls.m_vTranslateRoute.y, -8192.0f, 8192.0f, 0.1f);
pBank->AddSlider("Relative Z", &CWaypointRecording::ms_EditingControls.m_vTranslateRoute.z, -8192.0f, 8192.0f, 0.1f);
pBank->AddButton("Translate Now", CWaypointRecording::Edit_OnTranslateNow);
pBank->PopGroup();
pBank->PushGroup("Waypoint Flags");
pBank->AddToggle("Jump", &CWaypointRecording::ms_EditingControls.m_Flags.m_bJump, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Apply Jump Force", &CWaypointRecording::ms_EditingControls.m_Flags.m_bApplyJumpForce, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Land", &CWaypointRecording::ms_EditingControls.m_Flags.m_bLand, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Flip Backwards (Skiing)", &CWaypointRecording::ms_EditingControls.m_Flags.m_bFlipBackwards, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Flip Forwards (Skiing)", &CWaypointRecording::ms_EditingControls.m_Flags.m_bFlipForwards, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Drop Down (On-Foot)", &CWaypointRecording::ms_EditingControls.m_Flags.m_bDropDown, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Surfacing From Underwater (Swimming)", &CWaypointRecording::ms_EditingControls.m_Flags.m_bSurfacingFromUnderwater, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Vehicle", &CWaypointRecording::ms_EditingControls.m_Flags.m_bVehicle, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->AddToggle("Non Interrupt", &CWaypointRecording::ms_EditingControls.m_Flags.m_bNonInterrupt, CWaypointRecording::Edit_CopyFlagsToWaypoint);
pBank->PopGroup();
pBank->PopGroup();
pBank->PushGroup("Dev Controls");
pBank->AddSlider("Max Waypoint Spacing (On-Foot)", &CWaypointRecording::ms_fMaxWaypointSpacingOnFoot, 1.0f, 40.0f, 1.0f);
pBank->AddSlider("Max Waypoint Spacing (Skiing)", &CWaypointRecording::ms_fMaxWaypointSpacingOnSkis, 1.0f, 40.0f, 1.0f);
pBank->AddSlider("Max Waypoint Spacing (Vehicle)", &CWaypointRecording::ms_fMaxWaypointSpacingInVehicle, 1.0f, 40.0f, 1.0f);
pBank->AddSlider("Max Plane Dist (On-Foot)", &CWaypointRecording::ms_fMaxPlaneDistOnFoot, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Max Plane Dist (Skiing)", &CWaypointRecording::ms_fMaxPlaneDistOnSkis, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Max Plane Dist (Vehicle)", &CWaypointRecording::ms_fMaxPlaneDistInVehicle, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Max MBR Delta (Skiing)", &CWaypointRecording::ms_fMBRDeltaForNewWaypointOnSkis, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Max MBR Delta (On-Foot)", &CWaypointRecording::ms_fMBRDeltaForNewWaypointOnFoot, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Max Velocity Delta (Vehicle)", &CWaypointRecording::ms_fMBRDeltaForNewWaypointInVehicle, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Target Radius (On-Foot)", &CTaskFollowWaypointRecording::ms_fTargetRadius_OnFoot, 0.1f, 10.0f, 0.1f);
pBank->AddSlider("Target Radius (Skiing)", &CTaskFollowWaypointRecording::ms_fTargetRadius_Skiing, 0.1f, 10.0f, 0.1f);
pBank->AddButton("Test GetWaypointDistanceFromStart(10)", TestGetWaypointDistanceFromStart);
pBank->AddButton("TestGetPlayerDistanceAlongRoute", TestGetPlayerDistanceAlongRoute);
pBank->PushGroup("Ski-Specific");
pBank->AddSlider("Heading tweak multiplier", &CTaskFollowWaypointRecording::ms_fSkiHeadingTweakMultiplier, 0.0f, 10.0f, 0.1f);
pBank->AddSlider("Heading tweak (backwards) multiplier", &CTaskFollowWaypointRecording::ms_fSkiHeadingTweakBackwardsMultiplier, 0.0f, 10.0f, 0.1f);
pBank->AddSlider("Heading tweak min speed-sqr", &CTaskFollowWaypointRecording::ms_fSkiHeadingTweakMinSpeedSqr, 0.0f, 100.0f, 0.1f);
pBank->PopGroup();
pBank->AddToggle("Force Jump Heading", &CTaskFollowWaypointRecording::ms_bForceJumpHeading);
pBank->AddToggle("Apply Helper Forces", &CTaskFollowWaypointRecording::ms_bUseHelperForces);
pBank->AddToggle("Debug Store", &CWaypointRecording::ms_bDisplayStore);
pBank->AddSlider("Debug Store Index", &CWaypointRecording::ms_iDebugStoreIndex, 0, CWaypointRecording::ms_iMaxNumLoaded, 1);
pBank->AddText("Test route", CWaypointRecording::ms_TestRouteName, 64, false);
pBank->AddButton("Test : Stream route", TestStreamRoute);
pBank->AddButton("Test : Remove route", TestRemoveRoute);
pBank->AddButton("Test : Load all requested (streaming)", TestStreamingLoadAllRequested);
pBank->AddButton("Test : Warp player to route start", WarpPlayerToRouteStart);
pBank->AddButton("Test : Start playback on focus ped using streamed recording", TestPlayStreamedRecordingOnFocusPed);
pBank->AddButton("Test : Spawn skiers for streamed recordings", SpawnSkiersForStreamedRecordings);
pBank->AddButton("Test : Pause focus ped", TestPauseFocusPed);
pBank->AddButton("Test : Pause focus ped and face player", TestPauseFocusPedAndFacePlayer);
pBank->AddButton("Test : Resume focus ped", TestResumeFocusPed);
pBank->AddSlider("Test : Override MBR", &fOverrideMBR, MOVEBLENDRATIO_STILL, MOVEBLENDRATIO_SPRINT, 0.1f);
pBank->AddButton("Test : Set override speed", TestOverrideSpeed);
pBank->AddButton("Test : Set use default speed", TestUseDefaultSpeed);
pBank->AddButton("Test : Follow route aiming at player", TestFollowRouteAimingAtPlayer);
pBank->AddButton("Test : Follow route shooting at player", TestFollowRouteShootingAtPlayer);
pBank->AddToggle("Test : Use \'Run and Gun\' for aiming/shooting", &bUseRunAndGun);
pBank->AddButton("Test : Stop aiming or shooting", TestStopAimingOrShooting);
pBank->PushGroup("Assisted Movement Integration");
pBank->AddButton("Test : Toggle use as \'assisted-movement\' route", ToggleUseAsAssistedMovementRoute);
pBank->AddSlider("Assisted Movement Path Width", &CWaypointRecording::ms_fAssistedMovementPathWidth, 0.0f, 16.0f, 0.5f);
pBank->AddSlider("Assisted Movement Tension", &CWaypointRecording::ms_fAssistedMovementPathTension, 0.0f, 1.0f, 0.1f);
pBank->PopGroup();
pBank->PopGroup();
pBank->PopGroup();
}
}
void CWaypointRecording::StartPlayback(CPed * pPed, bool bPlaybackVehicle)
{
Assert(!ms_bRecording);
Assert(ms_RecordingRoute.GetSize());
if(ms_RecordingRoute.GetSize() >= 2)
{
ms_pPed = pPed;
const ::CWaypointRecordingRoute::RouteData & wpt1 = ms_RecordingRoute.GetWaypoint(0);
const ::CWaypointRecordingRoute::RouteData & wpt2 = ms_RecordingRoute.GetWaypoint(1);
const float fHdg = fwAngle::GetRadianAngleBetweenPoints(wpt2.GetPosition().x, wpt2.GetPosition().y, wpt1.GetPosition().x, wpt1.GetPosition().y);
if (bPlaybackVehicle)
{
Assertf(pPed->GetMyVehicle(), "Trying to playback a vehicle waypoint recording on a ped with no vehicle!");
if (pPed->GetMyVehicle())
{
pPed->GetMyVehicle()->Teleport(wpt1.GetPosition(), fHdg);
sVehicleMissionParams params;
params.m_fCruiseSpeed = 64.0f;
params.m_fTargetArriveDist = 2.0f;
u32 iFlags = 0;
if (ms_bUseAISlowdown)
{
iFlags |= CTaskFollowWaypointRecording::Flag_VehiclesUseAISlowdown;
}
CTaskVehicleFollowWaypointRecording* pFollowWaypointTask = rage_new CTaskVehicleFollowWaypointRecording(&ms_RecordingRoute, params, 0, iFlags);
pFollowWaypointTask->SetLoopPlayback(ms_bLoopRoutePlayback);
CTaskControlVehicle* pTask = rage_new CTaskControlVehicle(pPed->GetMyVehicle(), pFollowWaypointTask);
pPed->GetPedIntelligence()->AddTaskAtPriority(pTask, PED_TASK_PRIORITY_PRIMARY);
}
}
else
{
pPed->GetPrimaryMotionTask()->ForceReset();
pPed->Teleport(wpt1.GetPosition(), fHdg);
CTaskFollowWaypointRecording * pFlwRec = rage_new CTaskFollowWaypointRecording(&ms_RecordingRoute);
pFlwRec->SetLoopPlayback(ms_bLoopRoutePlayback);
pPed->GetPedIntelligence()->AddTaskAtPriority(pFlwRec, PED_TASK_PRIORITY_PRIMARY);
}
}
}
void CWaypointRecording::StopPlayback()
{
if(ms_pPed)
ms_pPed->GetPedIntelligence()->ClearTasks();
}
void CWaypointRecording::StartRecording(CPed * pPed, bool bRecordVehicle)
{
Assert(!ms_bRecording);
ms_bRecording = true;
ms_bWasFlipped = false;
ms_bUnderwaterLastFrame = false;
ms_bRecordingVehicle = bRecordVehicle;
ms_pPed = pPed;
ms_EditingControls.m_iSelectedWaypoint = 0;
if (bRecordVehicle)
{
Assertf(pPed->GetMyVehicle(), "Trying to start a vehicle waypoint recording but not in a vehicle!");
if (pPed->GetMyVehicle())
{
ms_RecordingRoute.AddWaypoint(VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(pPed->GetMyVehicle(), false)), Max(1.0f, pPed->GetMyVehicle()->GetVelocity().Mag()), pPed->GetMyVehicle()->GetTransform().GetHeading(), ::CWaypointRecordingRoute::WptFlag_Vehicle);
}
else
{
ms_bRecording = false;
}
}
else
{
Vector2 vMBR;
pPed->GetMotionData()->GetCurrentMoveBlendRatio(vMBR);
ms_RecordingRoute.AddWaypoint(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()), vMBR.y, pPed->GetCurrentHeading(), 0);
}
}
void CWaypointRecording::StopRecording()
{
ms_bRecording = false;
ms_EditingControls.m_iSelectedWaypoint = 0;
}
void CWaypointRecording::ClearRoute()
{
StopRecording();
ms_RecordingRoute.Clear();
CWaypointRecording::m_iLoadedRouteNumWaypoints = 0;
CWaypointRecording::m_LoadedRouteName[0] = 0;
}
void CWaypointRecording::Edit_InitWaypointWidgets()
{
if(ms_EditingControls.m_iSelectedWaypoint >= 0 && ms_EditingControls.m_iSelectedWaypoint < ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
ms_EditingControls.m_fWaypointHeading = wpt.GetHeading();
ms_EditingControls.m_fWaypointMBR = wpt.GetSpeed();
ms_EditingControls.m_Flags.m_bJump = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_Jump) != 0;
ms_EditingControls.m_Flags.m_bApplyJumpForce = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_ApplyJumpForce) != 0;
ms_EditingControls.m_Flags.m_bLand = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_Land) != 0;
ms_EditingControls.m_Flags.m_bVehicle = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_Vehicle) != 0;
ms_EditingControls.m_Flags.m_bFlipBackwards = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_SkiFlipBackwards) != 0;
ms_EditingControls.m_Flags.m_bFlipForwards = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_SkiFlipForwards) != 0;
ms_EditingControls.m_Flags.m_bDropDown = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_DropDown) != 0;
ms_EditingControls.m_Flags.m_bSurfacingFromUnderwater = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_SurfacingFromUnderwater) != 0;
ms_EditingControls.m_Flags.m_bNonInterrupt = (wpt.GetFlags() & ::CWaypointRecordingRoute::WptFlag_NonInterrupt) != 0;
ms_EditingControls.m_fFreeSpaceToLeft = wpt.GetFreeSpaceToLeft();
ms_EditingControls.m_fFreeSpaceToRight = wpt.GetFreeSpaceToRight();
}
}
void CWaypointRecording::Edit_CopyFlagsToWaypoint()
{
if(ms_EditingControls.m_iSelectedWaypoint >= 0 && ms_EditingControls.m_iSelectedWaypoint < ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
u32 iFlags = 0;
if(ms_EditingControls.m_Flags.m_bJump) iFlags |= ::CWaypointRecordingRoute::WptFlag_Jump;
if(ms_EditingControls.m_Flags.m_bApplyJumpForce) iFlags |= ::CWaypointRecordingRoute::WptFlag_ApplyJumpForce;
if(ms_EditingControls.m_Flags.m_bLand) iFlags |= ::CWaypointRecordingRoute::WptFlag_Land;
if(ms_EditingControls.m_Flags.m_bVehicle) iFlags |= ::CWaypointRecordingRoute::WptFlag_Vehicle;
if(ms_EditingControls.m_Flags.m_bFlipBackwards) iFlags |= ::CWaypointRecordingRoute::WptFlag_SkiFlipBackwards;
if(ms_EditingControls.m_Flags.m_bFlipForwards) iFlags |= ::CWaypointRecordingRoute::WptFlag_SkiFlipForwards;
if(ms_EditingControls.m_Flags.m_bDropDown) iFlags |= ::CWaypointRecordingRoute::WptFlag_DropDown;
if(ms_EditingControls.m_Flags.m_bSurfacingFromUnderwater) iFlags |= ::CWaypointRecordingRoute::WptFlag_SurfacingFromUnderwater;
if(ms_EditingControls.m_Flags.m_bNonInterrupt) iFlags |= ::CWaypointRecordingRoute::WptFlag_NonInterrupt;
wpt.SetFlags(iFlags);
}
}
void CWaypointRecording::Edit_OnChangeWaypoint()
{
ms_EditingControls.m_iSelectedWaypoint = Min(ms_EditingControls.m_iSelectedWaypoint, ms_RecordingRoute.GetSize()-1);
ms_EditingControls.m_iSelectedWaypoint = Max(ms_EditingControls.m_iSelectedWaypoint, 0);
Edit_InitWaypointWidgets();
}
void CWaypointRecording::Edit_RepositionWaypoint()
{
ms_EditingControls.ms_bRepositioningWaypoint = true;
}
void CWaypointRecording::Edit_InsertWaypoint()
{
// To insert a waypoint, there must be two or more waypoints already in existence in this route..
// The currently selected waypoint must not be the last in the route. The new waypoint will be created between the
// currently selected waypoint, and the one following it.
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >= 0 && ms_EditingControls.m_iSelectedWaypoint < ms_RecordingRoute.GetSize())
{
int iIndex = ms_EditingControls.m_iSelectedWaypoint+1;
bool bAddedOk = false;
// Insert between two waypoints?
if(iIndex < ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & prevWpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
::CWaypointRecordingRoute::RouteData & nextWpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint+1);
bAddedOk = ms_RecordingRoute.InsertWaypoint(
iIndex,
(prevWpt.GetPosition()+nextWpt.GetPosition())*0.5f,
(prevWpt.GetSpeed()+nextWpt.GetSpeed())*0.5f,
fwAngle::LimitRadianAngle( (prevWpt.GetHeading()+nextWpt.GetHeading())*0.5f ),
0
);
}
// Insert at end - extend route
else
{
::CWaypointRecordingRoute::RouteData & prevWpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
static const float fExtendDist = 0.5f;
Vector3 vExtendDir;
float fHdg;
if(ms_EditingControls.m_iSelectedWaypoint > 0)
{
::CWaypointRecordingRoute::RouteData & prevPrevWpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint-1);
vExtendDir = prevWpt.GetPosition() - prevPrevWpt.GetPosition();
vExtendDir.z = 0.0f;
vExtendDir.Normalize();
vExtendDir *= fExtendDist;
fHdg = fwAngle::GetRadianAngleBetweenPoints(vExtendDir.x, vExtendDir.y, 0.0f, 0.0f);
}
else
{
vExtendDir = Vector3(-rage::Sinf(prevWpt.GetHeading()), rage::Cosf(prevWpt.GetHeading()), 0.0f) * fExtendDist;
fHdg = prevWpt.GetHeading();
}
bAddedOk = ms_RecordingRoute.InsertWaypoint(
iIndex,
prevWpt.GetPosition() + vExtendDir,
prevWpt.GetSpeed(),
fwAngle::LimitRadianAngle(fHdg),
0
);
}
if(!bAddedOk)
{
Assertf(false, "Waypoint not inserted - maximum number of waypoints reached (%i)", ::CWaypointRecordingRoute::ms_iMaxNumWaypoints);
return;
}
m_iLoadedRouteNumWaypoints = ms_RecordingRoute.GetSize();
if(iIndex != -1)
{
ms_EditingControls.m_iSelectedWaypoint = iIndex;
ms_EditingControls.m_iSelectedWaypoint = Min(ms_EditingControls.m_iSelectedWaypoint, ms_RecordingRoute.GetSize()-1);
ms_EditingControls.m_iSelectedWaypoint = Max(ms_EditingControls.m_iSelectedWaypoint, 0);
Edit_InitWaypointWidgets();
}
}
}
void CWaypointRecording::Edit_RemoveWaypoint()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1 && ms_RecordingRoute.GetSize() > 1 )
{
ms_RecordingRoute.RemoveWaypoint(ms_EditingControls.m_iSelectedWaypoint);
ms_EditingControls.m_iSelectedWaypoint = Min(ms_EditingControls.m_iSelectedWaypoint, ms_RecordingRoute.GetSize()-1);
ms_EditingControls.m_iSelectedWaypoint = Max(ms_EditingControls.m_iSelectedWaypoint, 0);
m_iLoadedRouteNumWaypoints = ms_RecordingRoute.GetSize();
Edit_InitWaypointWidgets();
}
}
void CWaypointRecording::Edit_OnModifyHeading()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.SetHeading(ms_EditingControls.m_fWaypointHeading);
}
}
void CWaypointRecording::Edit_OnModifyMBR()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.SetSpeed(ms_EditingControls.m_fWaypointMBR);
}
}
void CWaypointRecording::Edit_OnModifyDistLeft()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.SetFreeSpaceToLeft(ms_EditingControls.m_fFreeSpaceToLeft);
}
}
void CWaypointRecording::Edit_OnModifyDistRight()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.SetFreeSpaceToRight(ms_EditingControls.m_fFreeSpaceToRight);
}
}
void CWaypointRecording::Edit_OnIncreaseX()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.m_fXYZ[0] += 0.1f;
}
}
void CWaypointRecording::Edit_OnDecreaseX()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.m_fXYZ[0] -= 0.1f;
}
}
void CWaypointRecording::Edit_OnIncreaseY()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.m_fXYZ[1] += 0.1f;
}
}
void CWaypointRecording::Edit_OnDecreaseY()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.m_fXYZ[1] -= 0.1f;
}
}
void CWaypointRecording::Edit_OnIncreaseZ()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.m_fXYZ[2] += 0.1f;
}
}
void CWaypointRecording::Edit_OnDecreaseZ()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.m_fXYZ[2] -= 0.1f;
}
}
void CWaypointRecording::Edit_OnTranslateNow()
{
if(ms_bWaypointEditing)
{
for(int i=0; i<ms_RecordingRoute.GetSize(); i++)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(i);
wpt.m_fXYZ[0] += ms_EditingControls.m_vTranslateRoute.x;
wpt.m_fXYZ[1] += ms_EditingControls.m_vTranslateRoute.y;
wpt.m_fXYZ[2] += ms_EditingControls.m_vTranslateRoute.z;
}
}
}
void CWaypointRecording::Edit_OnApplyAllDistances()
{
if (ms_bWaypointEditing)
{
for (int i=0; i < ms_RecordingRoute.GetSize(); i++)
{
::CWaypointRecordingRoute::RouteData& wpt = ms_RecordingRoute.GetWaypoint(i);
wpt.SetFreeSpaceToLeft(ms_EditingControls.m_fFreeSpaceToLeft);
wpt.SetFreeSpaceToRight(ms_EditingControls.m_fFreeSpaceToRight);
}
}
}
void CWaypointRecording::Edit_OnWarpToWaypoint()
{
if(ms_bWaypointEditing && ms_EditingControls.m_iSelectedWaypoint >=0 && ms_EditingControls.m_iSelectedWaypoint <= ms_RecordingRoute.GetSize()-1)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->Teleport( wpt.GetPosition(), wpt.GetHeading() );
}
}
}
void CWaypointRecording::Edit_OnSnapToGround()
{
if (ms_bWaypointEditing)
{
static dev_float s_fMaxSnap = 50.0f;
for (int i=0; i < ms_RecordingRoute.GetSize(); i++)
{
::CWaypointRecordingRoute::RouteData& wpt = ms_RecordingRoute.GetWaypoint(i);
Vector3 vPos = wpt.GetPosition();
CStreaming::LoadAllRequestedObjects();
CPhysics::LoadAboutPosition(RCC_VEC3V(vPos));
CStreaming::LoadAllRequestedObjects();
const float fNearestHeight = ThePaths.FindNearestGroundHeightForBuildPaths(vPos, s_fMaxSnap, NULL);
if (rage::Abs(fNearestHeight - vPos.z) < s_fMaxSnap)
{
vPos.z = fNearestHeight;
wpt.SetPosition(vPos);
}
}
}
}
void CWaypointRecording::Debug()
{
#if DEBUG_DRAW
if(ms_bDebugDraw)
{
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
char tmp[256];
ms_RecordingRoute.Draw(true);
for(int s=0; s<ms_iMaxNumLoaded; s++)
{
if(ms_LoadedRecordings[s].m_pRecording)
{
Vector3 vClosestPos = ms_LoadedRecordings[s].m_pRecording->GetClosestPosition(vOrigin);
sprintf(tmp, "routename : %s", ms_LoadedRecordings[s].m_Filename);
grcDebugDraw::Text(vClosestPos + ZAXIS, Color_green, tmp);
ms_LoadedRecordings[s].m_pRecording->Draw(false);
}
}
if(ms_bWaypointEditing)
{
if(ms_EditingControls.m_iSelectedWaypoint >= 0 && ms_EditingControls.m_iSelectedWaypoint < ms_RecordingRoute.GetSize())
{
const ::CWaypointRecordingRoute::RouteData & editWpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
Vector3 vEditPos = editWpt.GetPosition() + Vector3(0.0f,0.0f,2.0f);
const Color32 iEditCol1 = Color_white;
const Color32 iEditCol2 = Color_magenta3;
static float fEditBounceTheta = 0.0f;
static float fEditBounceRot = 0.0f;
fEditBounceTheta += fwTimer::GetTimeStep() * 3.0f;
while(fEditBounceTheta > TWO_PI) fEditBounceTheta -= TWO_PI;
fEditBounceRot += fwTimer::GetTimeStep() * 3.0f;
while(fEditBounceRot > TWO_PI) fEditBounceRot -= TWO_PI;
vEditPos.z += rage::Sinf(fEditBounceTheta) * 0.5f;
Vector3 vArrowCoords[] =
{
Vector3(0.0f, 0.25f, 1.0f),
Vector3(0.25f, 0.0f, 1.0f),
Vector3(0.0f, -0.25f, 1.0f),
Vector3(-0.25f, 0.0f, 1.0f)
};
Matrix34 rot;
rot.Identity();
rot.MakeRotateZ(fEditBounceRot);
rot.Transform(vArrowCoords[0]);
rot.Transform(vArrowCoords[1]);
rot.Transform(vArrowCoords[2]);
rot.Transform(vArrowCoords[3]);
grcDebugDraw::Line(vEditPos, vEditPos+vArrowCoords[0], iEditCol1, iEditCol2);
grcDebugDraw::Line(vEditPos, vEditPos+vArrowCoords[1], iEditCol1, iEditCol2);
grcDebugDraw::Line(vEditPos, vEditPos+vArrowCoords[2], iEditCol1, iEditCol2);
grcDebugDraw::Line(vEditPos, vEditPos+vArrowCoords[3], iEditCol1, iEditCol2);
grcDebugDraw::Line(vEditPos+vArrowCoords[0], vEditPos+vArrowCoords[1], iEditCol2, iEditCol2);
grcDebugDraw::Line(vEditPos+vArrowCoords[1], vEditPos+vArrowCoords[2], iEditCol2, iEditCol2);
grcDebugDraw::Line(vEditPos+vArrowCoords[2], vEditPos+vArrowCoords[3], iEditCol2, iEditCol2);
grcDebugDraw::Line(vEditPos+vArrowCoords[3], vEditPos+vArrowCoords[0], iEditCol2, iEditCol2);
}
}
}
if(ms_bDisplayStore)
{
for(int s=0; s<ms_iMaxNumLoaded; s++)
{
if(ms_LoadedRecordings[s].m_Filename[0])
{
grcDebugDraw::AddDebugOutput(Color_LightYellow, "%i) \"%s\" loaded=%s numrefs=%i", s, ms_LoadedRecordings[s].m_Filename, ms_LoadedRecordings[s].m_pRecording ? "true":"false", ms_LoadedRecordings[s].m_iNumReferences);
}
else
{
grcDebugDraw::AddDebugOutput(Color_LightYellow, "%i) ---", s);
}
}
}
#endif // DEBUG_DRAW
}
void CWaypointRecording::UpdateRecording()
{
// Handle the movement of individual waypoints
if(ms_bWaypointEditing && !ms_bRecording)
{
Vector3 mouseScreen, mouseFar;
CDebugScene::GetMousePointing(mouseScreen, mouseFar);
WorldProbe::CShapeTestProbeDesc probeDesc;
WorldProbe::CShapeTestFixedResults<> probeResult;
probeDesc.SetResultsStructure(&probeResult);
probeDesc.SetStartAndEnd(mouseScreen, mouseFar);
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES);
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc))
{
//****************************************
// Handle changing the selected waypoint
if(!ms_EditingControls.ms_bRepositioningWaypoint)
{
if(ioMouse::GetPressedButtons() & ioMouse::MOUSE_LEFT)
{
int iPrevSel = ms_EditingControls.m_iSelectedWaypoint;
static const float fSelectEpsSqr = 4.0f;
float fMinDistSqr = FLT_MAX;
for(int w=0; w<ms_RecordingRoute.GetSize(); w++)
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(w);
const Vector3 vDiff = probeResult[0].GetHitPosition() - wpt.GetPosition();
if(vDiff.Mag2() < fSelectEpsSqr && vDiff.Mag2() < fMinDistSqr)
{
ms_EditingControls.m_iSelectedWaypoint = w;
fMinDistSqr = vDiff.Mag2();
}
}
if(ms_EditingControls.m_iSelectedWaypoint != iPrevSel)
Edit_OnChangeWaypoint();
}
}
//*************************************
// Process repositioning the waypoint
if(ms_EditingControls.ms_bRepositioningWaypoint)
{
Vector3 mouseScreen, mouseFar;
CDebugScene::GetMousePointing(mouseScreen, mouseFar);
WorldProbe::CShapeTestProbeDesc probeDesc;
WorldProbe::CShapeTestFixedResults<> probeResult;
probeDesc.SetResultsStructure(&probeResult);
probeDesc.SetStartAndEnd(mouseScreen, mouseFar);
probeDesc.SetIncludeFlags(ArchetypeFlags::GTA_ALL_MAP_TYPES);
if(WorldProbe::GetShapeTestManager()->SubmitTest(probeDesc))
{
if(ms_EditingControls.m_iSelectedWaypoint >= 0 && ms_EditingControls.m_iSelectedWaypoint < ms_RecordingRoute.GetSize())
{
::CWaypointRecordingRoute::RouteData & wpt = ms_RecordingRoute.GetWaypoint(ms_EditingControls.m_iSelectedWaypoint);
wpt.SetPosition(probeResult[0].GetHitPosition());
}
}
if(ioMouse::GetPressedButtons() & ioMouse::MOUSE_LEFT)
ms_EditingControls.ms_bRepositioningWaypoint = false;
}
}
}
if(!ms_bRecording)
return;
// Handle the recording
Assert(ms_RecordingRoute.GetSize() > 0);
const ::CWaypointRecordingRoute::RouteData & waypointB = ms_RecordingRoute.GetWaypoint(ms_RecordingRoute.GetSize()-1);
const ::CWaypointRecordingRoute::RouteData & waypointA = ms_RecordingRoute.GetWaypoint(ms_RecordingRoute.GetSize() > 1 ? ms_RecordingRoute.GetSize()-2 : 0);
CVehicle* pVehicle = ms_bRecordingVehicle ? ms_pPed->GetMyVehicle() : NULL;
const float fVehicleVel = pVehicle ? pVehicle->GetVelocity().Mag() : 0.0f;
Vector2 vMBR;
ms_pPed->GetMotionData()->GetCurrentMoveBlendRatio(vMBR);
//don't let our velocity go under 1, since for vehicles it may cause them to stop moving
const float fMBRToUse = ms_bRecordingVehicle ? Max(fVehicleVel, 1.0f) : vMBR.y;
const float fDeltaMBR = fMBRToUse - waypointB.GetSpeed();
CEntity* pTestEntity = ms_bRecordingVehicle ? static_cast<CEntity*>(pVehicle) : static_cast<CEntity*>(ms_pPed);
Vector3 vTestPosition = ms_bRecordingVehicle ? VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(pVehicle, false))
: VEC3V_TO_VECTOR3(pTestEntity->GetTransform().GetPosition());
Vector3 vB = waypointB.GetPosition();
Vector3 vOtherB = VEC3V_TO_VECTOR3(pTestEntity->GetTransform().GetB());
Vector3 vA = (ms_RecordingRoute.GetSize() > 1) ? waypointA.GetPosition() : vB - vOtherB;
Vector3 vC = vTestPosition;
Vector3 vBC = vC - vB;
const float fDist = NormalizeAndMag(vBC);
vA.z = vB.z = vC.z;
const float fDistToLine = geomDistances::DistanceLineToPoint(vA, vB-vA, vC);
bool bJustJumped = false;
bJustJumped = (ms_pPed->GetPedResetFlag(CPED_RESET_FLAG_IsJumping) && (!(waypointB.GetFlags() & ::CWaypointRecordingRoute::WptFlag_Jump)));
const float fMaxWptSpacing = ms_bRecordingVehicle ? ms_fMaxWaypointSpacingInVehicle : ms_fMaxWaypointSpacingOnFoot;
const float fMaxPlaneDist = ms_bRecordingVehicle ? ms_fMaxPlaneDistInVehicle : ms_fMaxPlaneDistOnFoot;
const float fMaxDeltaMBR = ms_bRecordingVehicle ? ms_fMBRDeltaForNewWaypointInVehicle : ms_fMBRDeltaForNewWaypointOnFoot;
const bool bAddPointNormal =
((Abs(fDeltaMBR) > fMaxDeltaMBR || Abs(fDistToLine) > fMaxPlaneDist || fDist > fMaxWptSpacing)
&& fDist > ms_fMinWaypointSpacing);
const bool bInAir = ms_pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_IsInTheAir);
const bool bJustLanded = (waypointB.GetFlags() & ::CWaypointRecordingRoute::WptFlag_Jump) && !bInAir
&& !ms_pPed->GetPedResetFlag(CPED_RESET_FLAG_IsJumping);
const bool bSwimmingOnSurface = ms_pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_IsSwimming) &&
ms_pPed->GetPedIntelligence()->GetMotionTaskActiveSimplest() &&
ms_pPed->GetPedIntelligence()->GetMotionTaskActiveSimplest()->GetTaskType()==CTaskTypes::TASK_MOTION_SWIMMING;
const bool bSwimmingUnderwater = ms_pPed->GetPedConfigFlag(CPED_CONFIG_FLAG_IsSwimming) &&
ms_pPed->GetPedIntelligence()->GetMotionTaskActiveSimplest() &&
ms_pPed->GetPedIntelligence()->GetMotionTaskActiveSimplest()->GetTaskType()==CTaskTypes::TASK_MOTION_DIVING;
bool bFlip = false;
// We can't land & jump on the same waypoint. If we cancel the bJustJumped flag here,
// we will most likely detect the jump again the following frame.
if(bJustLanded)
bJustJumped = false;
//***************************
// Maybe add a waypoint here
if((bAddPointNormal && !bInAir && !ms_pPed->GetPedResetFlag( CPED_RESET_FLAG_IsJumping )) || bJustJumped || bJustLanded || bFlip)
{
bool bAddWpt = true;
if(ms_RecordingRoute.GetSize() > 0 && !bJustJumped && !bJustLanded)
{
const ::CWaypointRecordingRoute::RouteData & lastWpt = ms_RecordingRoute.GetWaypoint( ms_RecordingRoute.GetSize()-1 );
const Vector3 vLastPt = lastWpt.GetPosition();
if((vTestPosition - vLastPt).Mag2() < 1.0f)
bAddWpt = false;
}
u16 iFlags = 0;
if(bJustJumped)
iFlags |= ::CWaypointRecordingRoute::WptFlag_Jump;
else if(bJustLanded)
iFlags |= ::CWaypointRecordingRoute::WptFlag_Land;
if(bFlip)
{
if(!ms_bWasFlipped)
iFlags |= ::CWaypointRecordingRoute::WptFlag_SkiFlipBackwards;
else
iFlags |= ::CWaypointRecordingRoute::WptFlag_SkiFlipForwards;
}
if (ms_bRecordingVehicle)
{
iFlags |= ::CWaypointRecordingRoute::WptFlag_Vehicle;
}
if(bAddWpt)
{
if(bSwimmingOnSurface)
{
if(ms_bUnderwaterLastFrame)
{
iFlags |= ::CWaypointRecordingRoute::WptFlag_SurfacingFromUnderwater;
vTestPosition += Vector3(0.0f, 0.0f, 1.0f);
}
vTestPosition += Vector3(0.0f, 0.0f, 1.0f);
}
else
{
vTestPosition -= Vector3(0.0f, 0.0f, 1.0f);
}
//if this is a vehicle waypoint recording for a car or bike, not a boat or a plane
//(helis are planes--helis planes and boats are also technically cars)
//then snap the position to ground.
//I decided to do this here rather than in a second pass since we can be reasonably
//sure that collision is loaded for this point right now
if (ms_bRecordingVehicle && (pVehicle->InheritsFromAutomobile() || pVehicle->InheritsFromBike())
&& !pVehicle->InheritsFromBoat() && !pVehicle->InheritsFromPlane())
{
static dev_float s_fMaxSnap = 50.0f;
const float fNearestHeight = ThePaths.FindNearestGroundHeightForBuildPaths(vTestPosition, s_fMaxSnap, NULL);
if (rage::Abs(fNearestHeight - vTestPosition.z) < s_fMaxSnap)
{
vTestPosition.z = fNearestHeight;
}
}
const float fHeadingToUse = ms_bRecordingVehicle ? pVehicle->GetTransform().GetHeading() : ms_pPed->GetCurrentHeading();
ms_RecordingRoute.AddWaypoint(vTestPosition, fMBRToUse, fHeadingToUse, iFlags);
ms_bUnderwaterLastFrame = bSwimmingUnderwater;
}
}
// Toggle the flipped state
if(bFlip)
ms_bWasFlipped = !ms_bWasFlipped;
}
#endif // __BANK
bool CWaypointRecording::CheckWaypointRecordingName(const char * ASSERT_ONLY(pRecordingName))
{
#if __ASSERT
Assertf(pRecordingName && *pRecordingName, "Recording name was NULL");
if(!pRecordingName || !*pRecordingName)
return false;
// Ensure that the recording name is free of any path separators, or periods.
int iStrLen = istrlen(pRecordingName);
for(int c=0; c<iStrLen; c++)
{
/*
if(pRecordingName[c] == '\'' || pRecordingName[c] == '/' || pRecordingName[c] == '.' || pRecordingName[c] == ':')
{
Assertf(false, "Recording name must not include the path, or file extension");
return false;
}
*/
if(pRecordingName[c] == ' ' || pRecordingName[c] == '\t')
{
Assertf(false, "Recording name must not include spaces or tabs");
return false;
}
}
#endif
return true;
}
int CWaypointRecording::GetFreeRecordingSlot()
{
for(int r=0; r<ms_iMaxNumLoaded; r++)
{
if(ms_LoadedRecordings[r].m_iFileNameHashKey==0)
{
return r;
}
}
return -1;
}
int CWaypointRecording::FindExistingRecordingSlot(const u32 iHash)
{
for(int r=0; r<ms_iMaxNumLoaded; r++)
{
if(ms_LoadedRecordings[r].m_iFileNameHashKey==iHash)
{
return r;
}
}
return -1;
}
int CWaypointRecording::GetStreamingIndexForRecording(const u32 iHash)
{
const int cnt = GetMaxNumRecordingsPerLevel();
for(int i=0; i<cnt; i++)
{
if(m_StreamingInfo[i].m_iFilenameHashKey==iHash)
{
return i;
}
}
return -1;
}
int CWaypointRecording::FindSlotForPointer(const ::CWaypointRecordingRoute * pRec)
{
Assert(pRec);
if(!pRec)
return -1;
for(int r=0; r<ms_iMaxNumLoaded; r++)
{
if(ms_LoadedRecordings[r].m_pRecording==pRec)
{
return r;
}
}
return -1;
}
void CWaypointRecording::RequestRecording(const char * pRecordingName, const scrThreadId iScriptID)
{
const u32 iHash = atStringHash(pRecordingName);
//******************************************************
// Find the streaming index of this waypoint recording
int iStreamingIndex = GetStreamingIndexForRecording(iHash);
Assertf(iStreamingIndex != -1, "The requested waypoint route \'%s\' was not found in the .rpf", pRecordingName);
if(iStreamingIndex==-1)
return;
//***************************************************
// Try to obtain a slot for loading this recording
int s = FindExistingRecordingSlot(iHash);
if(s != -1)
{
if(ms_LoadedRecordings[s].m_pRecording)
{
//Assertf(false, "recording \'%s\' is already loaded", pRecordingName);
return;
}
#if __ASSERT && 0
GtaThread * pThread = ms_LoadedRecordings[s].m_iScriptID ? static_cast<GtaThread*>(scrThread::GetThread(ms_LoadedRecordings[s].m_iScriptID)) : NULL;
Assert(ms_LoadedRecordings[s].m_iNumReferences==0);
Assertf(ms_LoadedRecordings[s].m_iScriptID==iScriptID, "ERROR - Cannot request the same recording from different scripts. Memory will leak. Recording is \"%s\", this script is \"%s\", Original script is \"%s\"", pRecordingName, CTheScripts::GetCurrentScriptName(), pThread ? pThread->GetScriptName() : "NULL" );
#endif
}
else
{
s = GetFreeRecordingSlot();
if(s == -1)
{
Assertf(false, "CWaypointRecording - no free slots to load recording \'%s\'.", pRecordingName);
return;
}
Assert(ms_LoadedRecordings[s].m_iFileNameHashKey==0);
}
//*******************
// Set up the slot
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
Assert(rec.m_iNumReferences==0 && rec.m_pRecording==NULL);
rec.m_iFileNameHashKey = iHash;
rec.m_iNumReferences = 0;
rec.m_pRecording = NULL;
rec.m_iScriptID = iScriptID;
#if __BANK
strncpy(rec.m_Filename, pRecordingName, 64);
#endif
//*****************************
// Issue a streaming request
s32 flags = STRFLAG_FORCE_LOAD|STRFLAG_MISSION_REQUIRED;
CTheScripts::PrioritizeRequestsFromMissionScript(flags);
m_StreamingInterface.StreamingRequest(strLocalIndex(iStreamingIndex), flags);
}
void CWaypointRecording::RemoveRecording(const char * pRecordingName, const scrThreadId UNUSED_PARAM(iScriptID))
{
const u32 iHash = atStringHash(pRecordingName);
//******************************************************
// Find the streaming index of this waypoint recording
int iStreamingIndex = GetStreamingIndexForRecording(iHash);
Assertf(iStreamingIndex != -1, "The requested waypoint route \'%s\' was not found in the .rpf", pRecordingName);
if(iStreamingIndex==-1)
return;
//*****************************************************************************************************
// If an assisted movement route has been created from this waypoint recording, then ensure that this
// assisted movement route gets removed at the same time. We clear the flag, and force an update.
::CWaypointRecordingRoute * pRecording = GetRecording(pRecordingName);
if(pRecording)
{
u32 iFlags = pRecording->GetFlags();
if(iFlags & ::CWaypointRecordingRoute::RouteFlag_AssistedMovement)
{
iFlags &= ~::CWaypointRecordingRoute::RouteFlag_AssistedMovement;
pRecording->SetFlags(iFlags);
CAssistedMovementRouteStore::Process(FindPlayerPed(), true);
}
}
//****************************
// Issue a streaming remove..
// m_pRecording for the ms_LoadedRecordings entry will probably get cleared inside StreamingRemove
// so we have to search for the correct slot before calling StreamingRemove
if (pRecording)
{
int s = FindSlotForPointer(pRecording);
if(s != -1)
{
ms_LoadedRecordings[s].m_iScriptID = THREAD_INVALID;
}
}
m_StreamingInterface.ClearRequiredFlag(iStreamingIndex, STRFLAG_MISSION_REQUIRED);
m_StreamingInterface.StreamingRemove(strLocalIndex(iStreamingIndex));
}
void CWaypointRecording::RemoveAllRecordingsRequestedByScript(const scrThreadId iScriptID)
{
for(int s=0; s<ms_iMaxNumLoaded; s++)
{
if(ms_LoadedRecordings[s].m_pRecording && ms_LoadedRecordings[s].m_iScriptID==iScriptID)
{
int iStreamingIndex = GetStreamingIndexForRecording(ms_LoadedRecordings[s].m_iFileNameHashKey);
Assertf(iStreamingIndex != -1, "The requested waypoint route \'%s\' was not found in the .rpf", ms_LoadedRecordings[s].m_Filename);
if(iStreamingIndex==-1)
return;
ms_LoadedRecordings[s].m_iScriptID = THREAD_INVALID;
m_StreamingInterface.ClearRequiredFlag(iStreamingIndex, STRFLAG_MISSION_REQUIRED);
m_StreamingInterface.StreamingRemove(strLocalIndex(iStreamingIndex));
}
}
}
bool CWaypointRecording::IsRecordingLoaded(const char * pRecordingName)
{
const u32 iHash = atStringHash(pRecordingName);
int s = FindExistingRecordingSlot(iHash);
if(s == -1)
{
return false;
}
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
return (rec.m_pRecording != NULL);
}
bool CWaypointRecording::IsRecordingRequested(const char * pRecordingName)
{
const u32 iHash = atStringHash(pRecordingName);
int s = FindExistingRecordingSlot(iHash);
if(s == -1)
{
return false;
}
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
return (rec.m_pRecording == NULL);
}
bool CWaypointRecording::IncReferencesToRecording(const char * pRecordingName)
{
const u32 iHash = atStringHash(pRecordingName);
int s = FindExistingRecordingSlot(iHash);
if(s == -1)
{
Assertf(false, "Waypoint recording \'%s\' not found", pRecordingName);
return false;
}
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
if(rec.m_pRecording == NULL)
{
Assertf(false, "Waypoint recording \'%s\' not yet loaded", pRecordingName);
return false;
}
rec.m_iNumReferences++;
return true;
}
bool CWaypointRecording::IncReferencesToRecording(const ::CWaypointRecordingRoute * pRoute)
{
if(!pRoute)
{
return false;
}
int s = FindSlotForPointer(pRoute);
if(s == -1)
{
return false;
}
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
if(rec.m_pRecording == NULL)
{
Assertf(false, "recording not yet loaded");
return false;
}
rec.m_iNumReferences++;
return true;
}
bool CWaypointRecording::DecReferencesToRecording(const char * pRecordingName)
{
const u32 iHash = atStringHash(pRecordingName);
int s = FindExistingRecordingSlot(iHash);
if(s == -1)
{
// Not an error - this can happed when the game session is shutdown and recordings
// are removed whilst peds are still playing tasks which reference them.
//Assertf(false, "recording \'%s\' not found", pRecordingName);
return false;
}
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
if(rec.m_pRecording == NULL)
{
Assertf(false, "recording \'%s\' not yet loaded", pRecordingName);
return false;
}
#if AI_OPTIMISATIONS_OFF
Assertf(rec.m_iNumReferences > 0, "Dec-ref called on recording \'%s\' whose num refs is %i", pRecordingName, rec.m_iNumReferences);
#endif
rec.m_iNumReferences--;
rec.m_iNumReferences = Max(rec.m_iNumReferences, 0);
return true;
}
bool CWaypointRecording::DecReferencesToRecording(const ::CWaypointRecordingRoute * pRoute)
{
if(!pRoute)
{
return false;
}
int s = FindSlotForPointer(pRoute);
if(s == -1)
{
//Assertf(false, "recording not found");
return false;
}
CLoadedWaypointRecording & rec = ms_LoadedRecordings[s];
if(rec.m_pRecording == NULL)
{
Assertf(false, "recording not yet loaded");
return false;
}
#if AI_OPTIMISATIONS_OFF
Assertf(rec.m_iNumReferences > 0, "Dec-ref called on recording \'%p\' whose num refs is %i", pRoute, rec.m_iNumReferences);
#endif
rec.m_iNumReferences--;
return true;
}
::CWaypointRecordingRoute * CWaypointRecording::GetRecording(const char * pRecordingName)
{
const u32 iHash = atStringHash(pRecordingName);
int s = FindExistingRecordingSlot(iHash);
if(s != -1)
{
return ms_LoadedRecordings[s].m_pRecording;
}
return NULL;
}
::CWaypointRecordingRoute * CWaypointRecording::GetRecordingBySlotIndex(const int iSlotIndex)
{
if(iSlotIndex >= 0 && iSlotIndex < ms_iMaxNumLoaded)
{
return ms_LoadedRecordings[iSlotIndex].m_pRecording;
}
return NULL;
}
CLoadedWaypointRecording * CWaypointRecording::GetLoadedWaypointRecordingInfo(const ::CWaypointRecordingRoute * pRecording)
{
return GetLoadedWaypointRecordingInfo(FindSlotForPointer(pRecording));
}
CLoadedWaypointRecording * CWaypointRecording::GetLoadedWaypointRecordingInfo(const int iSlot)
{
if(iSlot >= 0)
{
return &ms_LoadedRecordings[iSlot];
}
return NULL;
}
void CWaypointRecording::SetRecordingFromStreamingIndex(s32 iStreamingIndex, ::CWaypointRecordingRoute * pRec)
{
Assert(iStreamingIndex >= 0 && iStreamingIndex < GetMaxNumRecordingsPerLevel());
const u32 iHashKey = m_StreamingInfo[iStreamingIndex].m_iFilenameHashKey;
Assert(iHashKey);
if(!iHashKey)
return;
for(int s=0; s<ms_iMaxNumLoaded; s++)
{
if(ms_LoadedRecordings[s].m_iFileNameHashKey == iHashKey)
{
Assertf(ms_LoadedRecordings[s].m_pRecording == NULL, "Setting recording into streaming slot - but m_pRecording wasn't NULL");
Assertf(ms_LoadedRecordings[s].m_iNumReferences==0, "Setting recording into streaming slot - but num refs wasn't zero");
ms_LoadedRecordings[s].m_pRecording = pRec;
ms_LoadedRecordings[s].m_iNumReferences = 0;
return;
}
}
Assertf(false, "Couldn't find the streaming slot in which to put newly loaded waypoint-recording..");
}
//*************************************************************************************
// Implement the streaming interface
#if !__FINAL
const char* CWaypointRecordingStreamingInterface::GetName(strLocalIndex index) const
{
return CWaypointRecording::m_StreamingInfo[index.Get()].m_Filename;
}
#endif
strLocalIndex CWaypointRecordingStreamingInterface::FindSlot(const char* name) const
{
u32 nameHash = atStringHash(name);
const int cnt = GetMaxNumRecordingsPerLevel();
for(int i=0; i<cnt; i++)
if(CWaypointRecording::m_StreamingInfo[i].m_iFilenameHashKey==nameHash)
return strLocalIndex(i);
return strLocalIndex(-1);
}
strLocalIndex CWaypointRecordingStreamingInterface::Register(const char* name)
{
// Assert(FindSlot(name) == -1);
// When starting a new session, the name will already be in this array so clear its entry now.
// During development, someone could add a waypoint to the .rpf and use askBeforeRestart to
// start a new session. In this case, the indices for all the following waypoint files will be one higher
// than in the previous session. The code below doesn't handle the case of a waypoint file being removed
// from the rpf between sessions.
// In all other cases, the index for a waypoint file should be identical between sessions.
int ExistingSlot = FindSlot(name).Get();
if (ExistingSlot >= 0)
{
CWaypointRecording::m_StreamingInfo[ExistingSlot].m_iFilenameHashKey = 0;
#if !__FINAL
CWaypointRecording::m_StreamingInfo[ExistingSlot].m_Filename[0] = 0;
#endif
}
const int cnt = GetMaxNumRecordingsPerLevel();
for(int i=0; i<cnt; i++)
{
if(CWaypointRecording::m_StreamingInfo[i].m_iFilenameHashKey==0)
{
CWaypointRecording::m_StreamingInfo[i].m_iFilenameHashKey = atStringHash(name);
#if !__FINAL
strncpy(CWaypointRecording::m_StreamingInfo[i].m_Filename, name, 64);
#endif
#if USE_PAGED_POOLS_FOR_STREAMING
AllocateSlot(i);
#endif // USE_PAGED_POOLS_FOR_STREAMING
return strLocalIndex(i);
}
}
Assertf(false, "Too many waypoint recordings in this level, max is %d", GetMaxNumRecordingsPerLevel());
return strLocalIndex(-1);
}
void CWaypointRecordingStreamingInterface::Remove(strLocalIndex index)
{
const u32 iHashKey = CWaypointRecording::m_StreamingInfo[index.Get()].m_iFilenameHashKey;
Assertf(iHashKey!=0, "Filename hashkey was zero - recording isn't loaded");
for(int l=0; l<CWaypointRecording::ms_iMaxNumLoaded; l++)
{
if(CWaypointRecording::ms_LoadedRecordings[l].m_iFileNameHashKey == iHashKey)
{
//Assertf(CWaypointRecording::ms_LoadedRecordings[l].m_iNumReferences==0, "Deleting waypoint recording \'%s\', but a ped was still following this route - the task may crash (numrefs: %i)", CWaypointRecording::m_StreamingInfo[index].m_Filename, CWaypointRecording::ms_LoadedRecordings[l].m_iNumReferences);
//**********************************************************************************************
// If this route is being removed, and peds are using it - then find which peds are running the
// waypoint-following task, and abort the task.
// TODO: Fix this, see (url:bugstar:1402103)
if(CWaypointRecording::ms_LoadedRecordings[l].m_iNumReferences)
{
CTask::Pool * pTaskPool = CTask::GetPool();
for(s32 t=0; t<pTaskPool->GetSize(); t++)
{
CTask * pTask = pTaskPool->GetSlot(t);
if(pTask)
{
if(pTask->GetTaskType()==CTaskTypes::TASK_FOLLOW_WAYPOINT_RECORDING)
{
CTaskFollowWaypointRecording * pFollowTask = ((CTaskFollowWaypointRecording*)pTask);
if(pFollowTask->GetRoute()==CWaypointRecording::ms_LoadedRecordings[l].m_pRecording)
{
if(pFollowTask->GetEntity())
pFollowTask->MakeAbortable( CTask::ABORT_PRIORITY_URGENT, NULL);
pFollowTask->ClearRoute();
pFollowTask->SetQuitImmediately();
}
}
else if(pTask->GetTaskType()==CTaskTypes::TASK_VEHICLE_FOLLOW_WAYPOINT_RECORDING)
{
CTaskVehicleFollowWaypointRecording* pFollowWaypointTask = ((CTaskVehicleFollowWaypointRecording*)pTask);
if (pFollowWaypointTask->GetRoute()==CWaypointRecording::ms_LoadedRecordings[l].m_pRecording)
{
if(pFollowWaypointTask->GetEntity())
pFollowWaypointTask->MakeAbortable(CTask::ABORT_PRIORITY_URGENT, NULL);
pFollowWaypointTask->ClearRoute();
pFollowWaypointTask->SetQuitImmediately();
}
}
}
}
}
delete CWaypointRecording::ms_LoadedRecordings[l].m_pRecording;
CWaypointRecording::ms_LoadedRecordings[l].m_iFileNameHashKey = 0;
CWaypointRecording::ms_LoadedRecordings[l].m_iNumReferences = 0;
CWaypointRecording::ms_LoadedRecordings[l].m_pRecording = NULL;
#if __BANK
CWaypointRecording::ms_LoadedRecordings[l].m_Filename[0] = 0;
#endif
}
}
}
void CWaypointRecordingStreamingInterface::RemoveSlot(strLocalIndex
#if USE_PAGED_POOLS_FOR_STREAMING || __ASSERT
index
#endif // USE_PAGED_POOLS_FOR_STREAMING || __ASSERT
)
{
ASSERT_ONLY(const u32 iHashKey = CWaypointRecording::m_StreamingInfo[index.Get()].m_iFilenameHashKey;)
Assert(iHashKey==0);
#if USE_PAGED_POOLS_FOR_STREAMING
FreeObject(index);
#endif // USE_PAGED_POOLS_FOR_STREAMING
}
bool CWaypointRecordingStreamingInterface::Load(strLocalIndex index, void * object, int size)
{
::CWaypointRecordingRoute * pRecordingRoute = rage_new ::CWaypointRecordingRoute();
char memFilename[256];
fiDeviceMemory::MakeMemoryFileName(memFilename, 256, object, size, false, "WaypointRecording");
if(pRecordingRoute->Load(memFilename))
{
// Put into the store
CWaypointRecording::SetRecordingFromStreamingIndex(index.Get(), pRecordingRoute);
return true;
}
return false;
}
void CWaypointRecordingStreamingInterface::PlaceResource(strLocalIndex index, datResourceMap& map, datResourceInfo& header)
{
::CWaypointRecordingRoute * pRecordingRoute = NULL;
#if __FINAL
pgRscBuilder::PlaceStream(pRecordingRoute, header, map, "<unknown>");
#else
char tmp[64];
sprintf(tmp, "::CWaypointRecordingRoute:%i", index.Get());
pgRscBuilder::PlaceStream(pRecordingRoute, header, map, tmp);
#endif
// Put into the store
CWaypointRecording::SetRecordingFromStreamingIndex(index.Get(), pRecordingRoute);
}
void* CWaypointRecordingStreamingInterface::GetPtr(strLocalIndex index)
{
const u32 iHashKey = CWaypointRecording::m_StreamingInfo[index.Get()].m_iFilenameHashKey;
Assertf(iHashKey!=0, "Filename hashkey was zero - recording isn't loaded");
for(int l=0; l<CWaypointRecording::ms_iMaxNumLoaded; l++)
{
if(CWaypointRecording::ms_LoadedRecordings[l].m_iFileNameHashKey == iHashKey)
{
return CWaypointRecording::ms_LoadedRecordings[l].m_pRecording;
}
}
return NULL;
}