2949 lines
93 KiB
C++
2949 lines
93 KiB
C++
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// FILE : script.cpp
|
||
// PURPOSE : Scripting and stuff.
|
||
// AUTHOR : Graeme & Obbe.
|
||
// anyway)
|
||
// CREATED : 12-11-99
|
||
//
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "script/script.h"
|
||
|
||
// Rage headers
|
||
#include "audioengine/engine.h"
|
||
#include "system/param.h"
|
||
#include "vector/quaternion.h"
|
||
|
||
// Framework headers
|
||
#include "fwnet/nettypes.h"
|
||
#include "fwscene/stores/mapdatastore.h"
|
||
#include "fwscript/scriptInterface.h"
|
||
|
||
// Security headers
|
||
#include "security/ragesecwinapi.h"
|
||
|
||
// Game headers
|
||
#include "animation/AnimScene/AnimSceneManager.h"
|
||
#include "audio/scriptaudioentity.h"
|
||
#include "camera/CamInterface.h"
|
||
#include "control/replay/replay.h"
|
||
#include "cutscene/CutSceneManagerNew.h"
|
||
#include "debug/BugstarIntegration.h"
|
||
#include "event/EventErrors.h"
|
||
#include "event/EventGroup.h"
|
||
#include "event/EventNetwork.h"
|
||
#include "frontend/landing_page/LandingPageArbiter.h"
|
||
#include "frontend/landing_page/LandingPageConfig.h"
|
||
#include "Network/Events/NetworkEventTypes.h"
|
||
#include "Network/Network.h"
|
||
#include "Network/NetworkInterface.h"
|
||
#include "Network/Live/NetworkTelemetry.h"
|
||
#include "Objects/DummyObject.h"
|
||
#include "Objects/object.h"
|
||
#include "peds/ped.h"
|
||
#include "peds/Ped.h"
|
||
#include "scene/MapChange.h"
|
||
#include "scene/ExtraContentDefs.h"
|
||
#include "scene/worldpoints.h"
|
||
#include "scene/world/GameWorld.h"
|
||
#include "script/commands_apps.h"
|
||
#include "script/commands_audio.h"
|
||
#include "script/commands_brains.h"
|
||
#include "script/commands_camera.h"
|
||
#include "script/commands_cutscene.h"
|
||
#include "script/commands_datafile.h"
|
||
#include "script/commands_debug.h"
|
||
#include "script/commands_decorator.h"
|
||
#include "script/commands_extrametadata.h"
|
||
#include "script/commands_entity.h"
|
||
#include "script/commands_event.h"
|
||
#include "script/commands_gamestream.h"
|
||
#include "script/commands_gang.h"
|
||
#include "script/commands_hud.h"
|
||
#include "script/commands_interiors.h"
|
||
#include "script/commands_itemsets.h"
|
||
#include "script/commands_landingpage.h"
|
||
#include "script/commands_law.h"
|
||
#include "script/commands_localization.h"
|
||
#include "script/commands_misc.h"
|
||
#include "script/commands_money.h"
|
||
#include "script/commands_object.h"
|
||
#include "script/commands_pad.h"
|
||
#include "script/commands_path.h"
|
||
#include "script/commands_ped.h"
|
||
#include "script/commands_player.h"
|
||
#include "script/commands_physics.h"
|
||
#include "script/commands_script.h"
|
||
#include "script/commands_security.h"
|
||
#include "script/commands_shapetest.h"
|
||
#include "script/commands_socialclub.h"
|
||
#include "script/commands_stats.h"
|
||
#include "script/commands_streaming.h"
|
||
#include "script/commands_task.h"
|
||
#include "script/commands_vehicle.h"
|
||
#include "script/commands_volume.h"
|
||
#include "script/commands_weapon.h"
|
||
#include "script/commands_fire.h"
|
||
#include "script/commands_zone.h"
|
||
#include "script/commands_graphics.h"
|
||
#include "script/commands_clock.h"
|
||
#include "script/commands_network.h"
|
||
#include "script/commands_lobby.h"
|
||
#include "script/commands_inventory.h"
|
||
#include "script/commands_water.h"
|
||
#include "script/commands_xml.h"
|
||
#include "script/commands_ny.h"
|
||
#include "script/commands_dlc.h"
|
||
#include "script/commands_recording.h"
|
||
#include "script/commands_replay.h"
|
||
#include "script/commands_netshopping.h"
|
||
#include "script/commands_savemigration.h"
|
||
#include "script/script_areas.h"
|
||
#include "script/script_brains.h"
|
||
#include "script/script_cars_and_peds.h"
|
||
#include "script/script_debug.h"
|
||
#include "script/script_hud.h"
|
||
#include "script/handlers/GameScriptEntity.h"
|
||
#include "script/Handlers/GameScriptResources.h"
|
||
#include "script/script_helper.h"
|
||
#include "script/streamedscripts.h"
|
||
#include "script/script_channel.h"
|
||
#include "script/ScriptMetadataManager.h"
|
||
#include "security/plugins/apicheckplugin.h"
|
||
#include "streaming/streaming.h"
|
||
#include "system/controlMgr.h"
|
||
#include "system/exception.h"
|
||
#include "system/FileMgr.h"
|
||
#include "system/hangdetect.h"
|
||
#include "task/Scenario/info/ScenarioInfoManager.h"
|
||
#include "vfx/misc/MovieMeshManager.h"
|
||
#include "control/replay/replay.h"
|
||
|
||
SCRIPT_OPTIMISATIONS ()
|
||
NETWORK_OPTIMISATIONS ()
|
||
|
||
PARAM(startupscript, "[script] load and run this script in place of startup.sc");
|
||
|
||
PARAM(scriptInstructionLimit, "[script] set the maximum number of instructions per frame to something other than the default of 1,000,000");
|
||
|
||
PARAM(scriptProtectGlobals, "[script] protects scripts global memory outide of the script update process");
|
||
|
||
//Define a script assert channel
|
||
RAGE_DEFINE_CHANNEL(script)
|
||
RAGE_DEFINE_SUBCHANNEL(script,hud)
|
||
RAGE_DEFINE_SUBCHANNEL(script,camera)
|
||
|
||
CScriptsForBrains CTheScripts::ms_ScriptsForBrains;
|
||
CScriptBrainDispatcher CTheScripts::ms_ScriptBrainDispatcher;
|
||
|
||
bool CTheScripts::ms_bPlayerIsOnAMission = false;
|
||
bool CTheScripts::ms_bPlayerIsOnARandomEvent = false;
|
||
u32 CTheScripts::ms_Frack = 0xEBEFC45E;
|
||
parTree* CTheScripts::ms_pXmlTree = NULL;
|
||
parTreeNode* CTheScripts::ms_pCurrentXmlTreeNode = NULL;
|
||
bool CTheScripts::ms_bUpdatingScriptThreads = false;
|
||
bool CTheScripts::ms_bPlayerIsRepeatingAMission = false;
|
||
bool CTheScripts::ms_bPlayerIsInAnimalForm = false;
|
||
bool CTheScripts::ms_bIsInDirectorMode = false;
|
||
bool CTheScripts::ms_directorModeAvailable = true;
|
||
s32 CTheScripts::ms_customMPHudColor = HUD_COLOUR_INVALID;
|
||
|
||
CScriptPatrol CTheScripts::ms_ScriptPatrol;
|
||
|
||
CMissionReplayStats CTheScripts::ms_MissionReplayStats;
|
||
|
||
CHiddenObjects CTheScripts::ms_HiddenObjects;
|
||
|
||
atBinaryMap<CDLCScript*,u32> CDLCScript::ms_scripts;
|
||
|
||
|
||
#if __DEV
|
||
static bool bDisplayUsedScriptResources = false;
|
||
#endif
|
||
|
||
int CTheScripts::ms_NumberOfMiniGamesInProgress = 0;
|
||
|
||
#if !__PPU
|
||
bool CTheScripts::ms_bSinglePlayerRestoreHasJustOccurred = false;
|
||
#endif
|
||
|
||
#if __BANK
|
||
f32 CTheScripts::sm_fTimeFadedOut = 0.0f;
|
||
#endif // __BANK
|
||
|
||
#if !__FINAL
|
||
bool CTheScripts::ms_bScriptLaunched = false;
|
||
#endif //!__FINAL
|
||
|
||
sysTimer CTheScripts::sm_ScriptTimer;
|
||
|
||
char CTheScripts::ms_ContentIdOfCurrentUGCMission[RLUGC_MAX_CONTENTID_CHARS];
|
||
|
||
bool CTheScripts::ms_bAllowGameToPauseForStreaming = true;
|
||
bool CTheScripts::ms_bScenarioPedsCanBeGrabbedByScript = false;
|
||
bool CTheScripts::ms_bCodeRequestedAutosave = false;
|
||
bool CTheScripts::ms_bProcessingTheScriptsDuringGameInit = false;
|
||
CGameScriptHandlerMgr CTheScripts::ms_ScriptHandlerMgr(&CNetwork::GetBandwidthManager());
|
||
bool CTheScripts::ms_bKillingAllScriptThreads = false;
|
||
CScriptOpList CTheScripts::ms_scriptOpList;
|
||
|
||
static int s_InstructionLimit = 0;
|
||
|
||
GEN9_STANDALONE_ONLY(CTheScripts::InitState CTheScripts::ms_initState = CTheScripts::InitState::Uninitialized);
|
||
|
||
bool CTheScripts::GetClosestObjectCB(CEntity* pEntity, void* data)
|
||
{
|
||
Assert(pEntity);
|
||
ClosestObjectDataStruct* pClosestObjectData = reinterpret_cast<ClosestObjectDataStruct*>(data);
|
||
|
||
if (pClosestObjectData->bCheckModelIndex && (pEntity->GetModelIndex() != pClosestObjectData->ModelIndexToCheck) )
|
||
{
|
||
return true;
|
||
}
|
||
|
||
if (pClosestObjectData->bCheckStealableFlag)
|
||
{
|
||
scriptAssertf(pEntity->GetIsTypeObject(), "%s:GetClosestObjectCB - Object should be a real object (not a dummy) if you're checking if it's stealable. This is a code problem (probably not a script problem)", CTheScripts::GetCurrentScriptNameAndProgramCounter());
|
||
if (pEntity->GetIsTypeObject())
|
||
{
|
||
CObject *pObj = (CObject *) pEntity;
|
||
if (pObj->m_nObjectFlags.bIsStealable == false)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(!((1 << pEntity->GetOwnedBy()) & pClosestObjectData->nOwnedByMask))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
Vector3 DiffVector = VEC3V_TO_VECTOR3(pEntity->GetTransform().GetPosition()) - pClosestObjectData->CoordToCalculateDistanceFrom;
|
||
float ObjDistanceSquared = DiffVector.Mag2();
|
||
if (ObjDistanceSquared < pClosestObjectData->fClosestDistanceSquared)
|
||
{
|
||
pClosestObjectData->pClosestObject = pEntity;
|
||
pClosestObjectData->fClosestDistanceSquared = ObjDistanceSquared;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
bool CTheScripts::CountMissionEntitiesInAreaCB(CEntity* pEntity, void* data)
|
||
{
|
||
int* pNumberOfMissionEntities = reinterpret_cast<int*>(data);
|
||
|
||
if (IsMissionEntity(pEntity))
|
||
(*pNumberOfMissionEntities)++;
|
||
|
||
return(true);
|
||
}
|
||
|
||
bool CTheScripts::IsMissionEntity(CEntity * pEntity)
|
||
{
|
||
Assert(pEntity);
|
||
switch (pEntity->GetType())
|
||
{
|
||
case ENTITY_TYPE_VEHICLE :
|
||
if (((CVehicle *)pEntity)->PopTypeIsMission())
|
||
{
|
||
return true;
|
||
}
|
||
break;
|
||
|
||
case ENTITY_TYPE_PED :
|
||
if (((CPed *)pEntity)->PopTypeIsMission())
|
||
{
|
||
return true;
|
||
}
|
||
break;
|
||
|
||
case ENTITY_TYPE_OBJECT :
|
||
if (((CObject *)pEntity)->GetOwnedBy() == ENTITY_OWNEDBY_SCRIPT) // || (((CObject *)pEntity)->GetOwnedBy() == MISSION_BRAIN_OBJECT) )
|
||
{
|
||
return true;
|
||
}
|
||
break;
|
||
|
||
default :
|
||
break;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
extern scrCommandHash<scrCmd> s_CommandHash;
|
||
typedef void (*regFunction) ();
|
||
|
||
void CTheScripts::ScrambleAndRegister()
|
||
{
|
||
atArray<regFunction> sourceArray;
|
||
sourceArray.Reserve(100);
|
||
|
||
sourceArray.Push(netshopping_commands::SetupScriptCommands);
|
||
sourceArray.Push(script_commands::SetupScriptCommands);
|
||
sourceArray.Push(object_commands::SetupScriptCommands);
|
||
sourceArray.Push(xml_commands::SetupScriptCommands);
|
||
sourceArray.Push(volume_commands::SetupScriptCommands);
|
||
sourceArray.Push(brain_commands::SetupScriptCommands);
|
||
sourceArray.Push(replay_commands::SetupScriptCommands);
|
||
sourceArray.Push(weapon_commands::SetupScriptCommands);
|
||
sourceArray.Push(apps_commands::SetupScriptCommands);
|
||
sourceArray.Push(ped_commands::SetupScriptCommands);
|
||
sourceArray.Push(fire_commands::SetupScriptCommands);
|
||
sourceArray.Push(clock_commands::SetupScriptCommands);
|
||
sourceArray.Push(interior_commands::SetupScriptCommands);
|
||
sourceArray.Push(pad_commands::SetupScriptCommands);
|
||
sourceArray.Push(graphics_commands::SetupScriptCommands);
|
||
sourceArray.Push(inventory_commands::SetupScriptCommands);
|
||
sourceArray.Push(localization_commands::SetupScriptCommands);
|
||
sourceArray.Push(player_commands::SetupScriptCommands);
|
||
sourceArray.Push(physics_commands::SetupScriptCommands);
|
||
sourceArray.Push(entity_commands::SetupScriptCommands);
|
||
sourceArray.Push(task_commands::SetupScriptCommands);
|
||
sourceArray.Push(zone_commands::SetupScriptCommands);
|
||
sourceArray.Push(misc_commands::SetupScriptCommands);
|
||
sourceArray.Push(streaming_commands::SetupScriptCommands);
|
||
sourceArray.Push(socialclub_commands::SetupScriptCommands);
|
||
sourceArray.Push(law_commands::SetupScriptCommands);
|
||
sourceArray.Push(audio_commands::SetupScriptCommands);
|
||
sourceArray.Push(gta_commands::SetupScriptCommands);
|
||
sourceArray.Push(path_commands::SetupScriptCommands);
|
||
sourceArray.Push(itemsets_commands::SetupScriptCommands);
|
||
sourceArray.Push(datafile_commands::SetupScriptCommands);
|
||
sourceArray.Push(dlc_commands::SetupScriptCommands);
|
||
sourceArray.Push(cutscene_commands::SetupScriptCommands);
|
||
sourceArray.Push(stats_commands::SetupScriptCommands);
|
||
sourceArray.Push(shapetest_commands::SetupScriptCommands);
|
||
sourceArray.Push(recording_commands::SetupScriptCommands);
|
||
sourceArray.Push(extrametadata_commands::SetupScriptCommands);
|
||
sourceArray.Push(camera_commands::SetupScriptCommands);
|
||
sourceArray.Push(vehicle_commands::SetupScriptCommands);
|
||
sourceArray.Push(lobby_commands::SetupScriptCommands);
|
||
sourceArray.Push(event_commands::SetupScriptCommands);
|
||
sourceArray.Push(water_commands::SetupScriptCommands);
|
||
sourceArray.Push(money_commands::SetupScriptCommands);
|
||
sourceArray.Push(network_commands::SetupScriptCommands);
|
||
sourceArray.Push(debug_commands::SetupScriptCommands);
|
||
sourceArray.Push(gang_commands::SetupScriptCommands);
|
||
sourceArray.Push(decorator_commands::SetupScriptCommands);
|
||
sourceArray.Push(hud_commands::SetupScriptCommands);
|
||
sourceArray.Push(savemigration_commands::SetupScriptCommands);
|
||
sourceArray.Push(landingpage_commands::SetupScriptCommands);
|
||
sourceArray.Push(security_commands::SetupScriptCommands);
|
||
|
||
// scramble the function array
|
||
u32 size = sourceArray.GetCount();
|
||
for(u32 scrambleCount = 0; scrambleCount < 1000; scrambleCount++)
|
||
{
|
||
u32 randomIndex = fwRandom::GetRandomNumberInRange(0, size);
|
||
|
||
regFunction temp = sourceArray[randomIndex];
|
||
sourceArray.DeleteFast(randomIndex);
|
||
sourceArray.Push(temp);
|
||
}
|
||
|
||
// execute all the functions in the scambled array
|
||
for(u32 i = 0; i < sourceArray.GetCount(); i++)
|
||
{
|
||
sourceArray[i]();
|
||
}
|
||
ApiCheckPlugin_StopNativeHash();
|
||
|
||
s_CommandHash.RegistrationComplete(true);
|
||
}
|
||
|
||
void CTheScripts::RegisterScriptCommands()
|
||
{
|
||
#if 1
|
||
ScrambleAndRegister();
|
||
#else //
|
||
//@@: location CTHESCRIPTS_REGISTER_SCRIPTCOMMANDS
|
||
netshopping_commands::SetupScriptCommands();
|
||
script_commands::SetupScriptCommands();
|
||
object_commands::SetupScriptCommands();
|
||
xml_commands::SetupScriptCommands();
|
||
volume_commands::SetupScriptCommands();
|
||
brain_commands::SetupScriptCommands();
|
||
replay_commands::SetupScriptCommands();
|
||
weapon_commands::SetupScriptCommands();
|
||
apps_commands::SetupScriptCommands();
|
||
ped_commands::SetupScriptCommands();
|
||
fire_commands::SetupScriptCommands();
|
||
clock_commands::SetupScriptCommands();
|
||
interior_commands::SetupScriptCommands();
|
||
pad_commands::SetupScriptCommands();
|
||
graphics_commands::SetupScriptCommands();
|
||
inventory_commands::SetupScriptCommands();
|
||
localization_commands::SetupScriptCommands();
|
||
player_commands::SetupScriptCommands();
|
||
physics_commands::SetupScriptCommands();
|
||
entity_commands::SetupScriptCommands();
|
||
task_commands::SetupScriptCommands();
|
||
zone_commands::SetupScriptCommands();
|
||
misc_commands::SetupScriptCommands();
|
||
streaming_commands::SetupScriptCommands();
|
||
socialclub_commands::SetupScriptCommands();
|
||
law_commands::SetupScriptCommands();
|
||
audio_commands::SetupScriptCommands();
|
||
gta_commands::SetupScriptCommands();
|
||
path_commands::SetupScriptCommands();
|
||
itemsets_commands::SetupScriptCommands();
|
||
datafile_commands::SetupScriptCommands();
|
||
dlc_commands::SetupScriptCommands();
|
||
cutscene_commands::SetupScriptCommands();
|
||
stats_commands::SetupScriptCommands();
|
||
shapetest_commands::SetupScriptCommands();
|
||
recording_commands::SetupScriptCommands();
|
||
extrametadata_commands::SetupScriptCommands();
|
||
camera_commands::SetupScriptCommands();
|
||
vehicle_commands::SetupScriptCommands();
|
||
lobby_commands::SetupScriptCommands();
|
||
event_commands::SetupScriptCommands();
|
||
water_commands::SetupScriptCommands();
|
||
money_commands::SetupScriptCommands();
|
||
network_commands::SetupScriptCommands();
|
||
debug_commands::SetupScriptCommands();
|
||
gang_commands::SetupScriptCommands();
|
||
decorator_commands::SetupScriptCommands();
|
||
hud_commands::SetupScriptCommands();
|
||
savemigration_commands::SetupScriptCommands();
|
||
landingpage_commands::SetupScriptCommands();
|
||
security_commands::SetupScriptCommands();
|
||
#endif // 1
|
||
}
|
||
|
||
|
||
void CTheScripts::GtaFaultHandler(const char *ASSERT_ONLY(CauseOfFault), scrThread*, scrThreadFaultID faultType)
|
||
{
|
||
if (GetCurrentGtaScriptThread())
|
||
{
|
||
sErrorScriptID scriptID;
|
||
scriptID.m_scriptNameHash = GetCurrentGtaScriptThread()->m_HashOfScriptName;
|
||
|
||
switch(faultType)
|
||
{
|
||
case THREAD_ARRAY_OVERFLOW:
|
||
|
||
GetEventScriptErrorsGroup()->Add(CEventErrorArrayOverflow(scriptID));
|
||
break;
|
||
case THREAD_STACK_OVERFLOW:
|
||
GetEventScriptErrorsGroup()->Add(CEventErrorStackOverflow(scriptID));
|
||
break;
|
||
case THREAD_INSTRUCTION_COUNT_OVERFLOW:
|
||
GetEventScriptErrorsGroup()->Add(CEventErrorInstructionLimit(scriptID));
|
||
break;
|
||
case THREAD_UNKNOWN_ERROR_TYPE:
|
||
default:
|
||
GetEventScriptErrorsGroup()->Add(CEventErrorUnknownError(scriptID));
|
||
break;
|
||
}
|
||
|
||
#if __ASSERT
|
||
// display the program counter of the current script here
|
||
char ErrorString[1024];
|
||
sprintf(ErrorString, "%s : Program Counter = %d - Check the .scd file\n", GetCurrentScriptName(), GetCurrentGtaScriptThread()->GetThreadPC());
|
||
scriptAssertf(0, "%s:%s", ErrorString, CauseOfFault);
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
scriptAssertf(0, "%s:%s", "Unknown script name", CauseOfFault);
|
||
}
|
||
}
|
||
|
||
|
||
// KS - WR 156 - added stacksize argument
|
||
scrThreadId CTheScripts::GtaStartNewThreadOverride(const char *progname,const void *argStruct,int argStructSize, int stackSize)
|
||
{
|
||
if (!progname || (strlen(progname) == 0) )
|
||
{
|
||
if (GetCurrentGtaScriptThread())
|
||
{
|
||
scriptAssertf(0, "%s:CTheScripts::GtaStartNewThreadOverride - trying to start a script without passing in a script name", GetCurrentScriptNameAndProgramCounter());
|
||
}
|
||
else
|
||
{
|
||
scriptAssertf(0, "CTheScripts::GtaStartNewThreadOverride - trying to start a script without passing in a script name");
|
||
}
|
||
}
|
||
scrProgramId pid = scrProgram::IsCompiledAndResident(progname);
|
||
if (!pid)
|
||
{
|
||
strLocalIndex id = g_StreamedScripts.FindSlot(progname);
|
||
scriptAssertf(id != -1, "%s:Script doesn't exist", progname);
|
||
if (id == -1)
|
||
return THREAD_INVALID;
|
||
|
||
scriptAssertf(g_StreamedScripts.Get(id), "%s:Script is not in memory", progname);
|
||
|
||
scriptDisplayf("About to start script thread %s", progname);
|
||
pid = g_StreamedScripts.GetProgramId(id.Get());
|
||
}
|
||
|
||
return GtaStartNewThreadWithProgramId(pid, argStruct,argStructSize, stackSize, progname);
|
||
}
|
||
|
||
scrThreadId CTheScripts::GtaStartNewThreadWithNameHashOverride(atHashValue hashOfProgName,const void *argStruct,int argStructSize, int stackSize)
|
||
{
|
||
if (hashOfProgName.GetHash() == 0)
|
||
{
|
||
if (GetCurrentGtaScriptThread())
|
||
{
|
||
scriptAssertf(0, "%s:CTheScripts::GtaStartNewThreadWithNameHashOverride - the hash of the script to be started is 0", GetCurrentScriptNameAndProgramCounter());
|
||
}
|
||
else
|
||
{
|
||
scriptAssertf(0, "CTheScripts::GtaStartNewThreadWithNameHashOverride - the hash of the script to be started is 0");
|
||
}
|
||
}
|
||
|
||
// I'm not sure what to do with IsCompiledAndResident. It seems to be using a different hash function - scrComputeHash
|
||
scrProgramId pid = srcpidNONE; // = scrProgram::IsCompiledAndResident(progname);
|
||
// if (!pid)
|
||
{
|
||
strLocalIndex id = g_StreamedScripts.FindSlotFromHashKey(hashOfProgName.GetHash());
|
||
scriptAssertf(id != -1, "Script with hash %u doesn't exist", hashOfProgName.GetHash());
|
||
if (id == -1)
|
||
return THREAD_INVALID;
|
||
|
||
scriptAssertf(g_StreamedScripts.Get(id), "Script with hash %u is not in memory", hashOfProgName.GetHash());
|
||
|
||
scriptDisplayf("About to start script thread with hash %u", hashOfProgName.GetHash());
|
||
pid = g_StreamedScripts.GetProgramId(id.Get());
|
||
}
|
||
|
||
char debugStringContainingHash[32];
|
||
formatf(debugStringContainingHash, "0x%x", hashOfProgName.GetHash());
|
||
return GtaStartNewThreadWithProgramId(pid, argStruct,argStructSize, stackSize, debugStringContainingHash);
|
||
}
|
||
|
||
scrThreadId CTheScripts::GtaStartNewThreadWithProgramId(scrProgramId progId,const void *argStruct,int argStructSize,int stackSize, const char* OUTPUT_ONLY(progname) )
|
||
{
|
||
scrThreadId threadId = scrThread::CreateThread(progId, argStruct, argStructSize, stackSize);
|
||
|
||
#if !__NO_OUTPUT
|
||
if (threadId == THREAD_INVALID)
|
||
{
|
||
#if __BANK
|
||
GtaThread::DisplayAllRunningScripts(false);
|
||
#endif // __BANK
|
||
|
||
#if __ASSERT
|
||
scriptAssertf(0, "%s:Failed to create a new thread (stack %d)", progname, stackSize);
|
||
#else
|
||
scriptErrorf("%s:Failed to create a new thread (stack %d)", progname, stackSize);
|
||
#endif // __ASSERT
|
||
}
|
||
#endif // !__NO_OUTPUT
|
||
|
||
GtaThread *pNewOne = static_cast<GtaThread *> (scrThread::GetThread(threadId));
|
||
if (pNewOne == NULL)
|
||
{
|
||
#if __ASSERT
|
||
scriptAssertf(0, "CTheScripts::GtaStartNewThreadWithProgramId - Could not get a pointer to the new thread %s", progname);
|
||
#else
|
||
scriptErrorf("CTheScripts::GtaStartNewThreadWithProgramId - Could not get a pointer to the new thread %s", progname);
|
||
#endif // __ASSERT
|
||
|
||
return THREAD_INVALID;
|
||
}
|
||
pNewOne->Initialise();
|
||
|
||
ms_ScriptHandlerMgr.RegisterScript(*pNewOne);
|
||
|
||
#if __BANK
|
||
if (CScriptDebug::ShouldThisScriptBeDebugged(progname))
|
||
{
|
||
GtaThread::AllocateDebuggerForThread(threadId);
|
||
}
|
||
|
||
CScriptDebug::SetComboBoxOfThreadNamesNeedsUpdated(true);
|
||
#endif
|
||
|
||
#if BACKTRACE_ENABLED
|
||
sysException::BacktraceNotifyScriptLaunched((u32)progId, fwTimer::GetSystemTimeInMilliseconds());
|
||
#endif // BACKTRACE_ENABLED
|
||
|
||
scriptDisplayf("Started new script thread %s(%d) with stack size %d", progname, threadId, stackSize);
|
||
return threadId;
|
||
}
|
||
|
||
#if !__PPU
|
||
void CTheScripts::SetSinglePlayerRestoreHasJustOccurred(bool bRestoreJustOccurred)
|
||
{
|
||
ms_bSinglePlayerRestoreHasJustOccurred = bRestoreJustOccurred;
|
||
}
|
||
|
||
bool CTheScripts::GetSinglePlayerRestoreHasJustOccurred()
|
||
{
|
||
return ms_bSinglePlayerRestoreHasJustOccurred;
|
||
}
|
||
#endif // !__PPU
|
||
|
||
|
||
void CScriptPatrol::Init()
|
||
{
|
||
bPatrolRouteOpen = false;
|
||
ScriptPatrolNodeIndex = 0;
|
||
ScriptPatrolLinkIndex = 0;
|
||
ScriptPatrolRouteHash = 0;
|
||
|
||
// fwIplPatrolNode ScriptPatrolNodes[MAX_NUMBER_OF_PATROL_NODES];
|
||
// fwIplPatrolLink ScriptPatrolLinks[MAX_NUMBER_OF_PATROL_LINKS];
|
||
// int ScriptPatrolNodeIDs[MAX_NUMBER_OF_PATROL_NODES];
|
||
}
|
||
|
||
void CScriptPatrol::OpenPatrolRoute(const char* RouteName)
|
||
{
|
||
if (SCRIPT_VERIFY((strnicmp ("miss_", RouteName,5) == 0), "CScriptPatrol::OpenPatrolRoute - Script patrol routes name must start with miss_"))
|
||
{
|
||
if (SCRIPT_VERIFY(bPatrolRouteOpen == false, "CScriptPatrol::OpenPatrolRoute - Patrol route must be closed before being opened"))
|
||
{
|
||
ScriptPatrolRouteHash = atStringHash(RouteName);
|
||
bPatrolRouteOpen = true;
|
||
ScriptPatrolNodeIndex = 0;
|
||
ScriptPatrolLinkIndex = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CScriptPatrol::ClosePatrolRoute()
|
||
{
|
||
bPatrolRouteOpen = false;
|
||
}
|
||
|
||
void CScriptPatrol::AddPatrolNode(int NodeId, const char* NodeType, Vector3 &vNodePos, Vector3 &vNodeHeading, int Duration)
|
||
{
|
||
if (!vNodeHeading.IsZero())
|
||
{
|
||
vNodeHeading = vNodeHeading - vNodePos;
|
||
}
|
||
|
||
int iDuration = (int) Duration / 1000;
|
||
|
||
// Check if the node type references a valid scenario right away, rather than waiting for
|
||
// a more cryptic assert from the tasks.
|
||
u32 nodeTypeHash = atStringHash(NodeType);
|
||
scriptAssertf(!nodeTypeHash || SCENARIOINFOMGR.GetScenarioIndex(nodeTypeHash, false) >= 0,
|
||
"%s:ADD_PATROL_NODE - failed for find scenario '%s'.",
|
||
CTheScripts::GetCurrentScriptNameAndProgramCounter(), NodeType);
|
||
|
||
if (SCRIPT_VERIFY(bPatrolRouteOpen == true, "CScriptPatrol::AddPatrolNode- Patrol route must be open before adding nodes"))
|
||
{
|
||
if (SCRIPT_VERIFY((ScriptPatrolNodeIndex <= MAX_NUMBER_OF_PATROL_NODES - 1) , "CScriptPatrol::AddPatrolNode - Patrol route can have no more than 16 nodes"))
|
||
{
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].x = vNodePos.x;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].y = vNodePos.y;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].z = vNodePos.z;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].headingX = vNodeHeading.x;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].headingY = vNodeHeading.y;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].headingZ = vNodeHeading.z;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].nodeTypeHash = nodeTypeHash;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].routeNameHash = ScriptPatrolRouteHash;
|
||
ScriptPatrolNodes[ScriptPatrolNodeIndex].duration = iDuration;
|
||
ScriptPatrolNodeIDs[ScriptPatrolNodeIndex] = NodeId;
|
||
ScriptPatrolNodeIndex++;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CScriptPatrol::AddPatrolLink(int NodeID1, int NodeID2)
|
||
{
|
||
if (SCRIPT_VERIFY(bPatrolRouteOpen == true, "CScriptPatrol::AddPatrolLink - Patrol route must be open before adding nodes"))
|
||
{
|
||
if (SCRIPT_VERIFY(ScriptPatrolLinkIndex <= MAX_NUMBER_OF_PATROL_LINKS -1, "CScriptPatrol::AddPatrolLink - Patrol links must be less than 64"))
|
||
{
|
||
ScriptPatrolLinks[ScriptPatrolLinkIndex].node1 = NodeID1;
|
||
ScriptPatrolLinks[ScriptPatrolLinkIndex].node2 = NodeID2;
|
||
ScriptPatrolLinkIndex++;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CScriptPatrol::CreatePatrolRoute()
|
||
{
|
||
if (SCRIPT_VERIFY(bPatrolRouteOpen == false, "CScriptPatrol::CreatePatrolRoute - Must close the nodes before adding the route"))
|
||
{
|
||
CScriptResource_PatrolRoute patrolRoute(ScriptPatrolRouteHash, ScriptPatrolNodes, ScriptPatrolNodeIDs, ScriptPatrolNodeIndex, ScriptPatrolLinks, ScriptPatrolLinkIndex, 0);
|
||
CTheScripts::GetCurrentGtaScriptHandler()->RegisterScriptResource(patrolRoute);
|
||
}
|
||
}
|
||
|
||
void CTheScripts::Init(unsigned initMode)
|
||
{
|
||
USE_MEMBUCKET(MEMBUCKET_SCRIPT);
|
||
//@@: location CTHESCRIPTS_INIT_INIT_ENTRY_POINT
|
||
|
||
GtaThread::StaticInit(initMode);
|
||
|
||
if(initMode == INIT_CORE)
|
||
{
|
||
GEN9_STANDALONE_ONLY(Assertf(ms_initState == InitState::Uninitialized, "Unexpected state %d, should be %d", ms_initState, InitState::Uninitialized));
|
||
GEN9_STANDALONE_ONLY(ms_initState = InitState::Initialized);
|
||
|
||
RAGE_TRACK(CTheScripts);
|
||
|
||
#if ENABLE_SCRIPT_GLOBALS_HEAP
|
||
const int globalsHeapSize = fwConfigManager::GetInstance().GetSizeOfPool(atHashString("scrGlobals", 0xC780FC5), CONFIGURED_FROM_FILE);
|
||
sysMemStartPool();
|
||
u8* heapMem = rage_new u8[globalsHeapSize];
|
||
sysMemEndPool();
|
||
scrProgram::InitGlobalsHeap(heapMem, globalsHeapSize);
|
||
#endif // ENABLE_SCRIPT_GLOBALS_HEAP
|
||
|
||
scrProgram::InitClass();
|
||
scrThread::InitClass();
|
||
GtaThread::AllocateThreads();
|
||
ms_ScriptHandlerMgr.Init();
|
||
scriptInterface::Init(ms_ScriptHandlerMgr);
|
||
|
||
CGameScriptResource::Init(initMode);
|
||
//@@: location CTHESCRIPTS_INIT_INIT_SCRIPTSMETADATAMANAGER
|
||
CScriptMetadataManager::Init();
|
||
|
||
scrThread::AppFaultHandler = GtaFaultHandler;
|
||
scrThread::StartNewThreadOverride = GtaStartNewThreadOverride;
|
||
scrThread::StartNewThreadWithNameHashOverride = GtaStartNewThreadWithNameHashOverride;
|
||
|
||
#if !__PPU
|
||
ms_bSinglePlayerRestoreHasJustOccurred = false;
|
||
#endif
|
||
|
||
ms_bProcessingTheScriptsDuringGameInit = false;
|
||
|
||
// register commands
|
||
|
||
//@@: location CTHESCRIPTS_INIT_REGISTER_BUILTIN_COMMANDS
|
||
scrThread::RegisterBuiltinCommands();
|
||
|
||
RegisterScriptCommands();
|
||
|
||
#if SCRIPT_DEBUGGING
|
||
// Process the -nativetrace command line argument to update actions for specified natives
|
||
scrThread::ParseNativeTraceCommandLine();
|
||
#endif
|
||
|
||
ms_pXmlTree = NULL;
|
||
ms_pCurrentXmlTreeNode = NULL;
|
||
ms_bUpdatingScriptThreads = false;
|
||
|
||
s_InstructionLimit = 0;
|
||
#if !__FINAL
|
||
if (PARAM_scriptInstructionLimit.Get())
|
||
{
|
||
PARAM_scriptInstructionLimit.Get(s_InstructionLimit);
|
||
}
|
||
#endif // !__FINAL
|
||
|
||
#if RSG_PC && ENABLE_SCRIPT_TAMPER_CHECKER
|
||
// Add the listener
|
||
CScriptGlobalTamperChecker::Initialize();
|
||
#endif
|
||
}
|
||
|
||
#if GEN9_STANDALONE_ENABLED
|
||
// We want to run this exactly once during INIT_CORE for first launch. If the game session is
|
||
// subsequently shut down, we want to run this again when it is rebuilt during INIT_SESSION.
|
||
if(ms_initState == InitState::Initialized)
|
||
#else
|
||
if (initMode == INIT_SESSION)
|
||
#endif // GEN9_STANDALONE_ENABLED
|
||
{
|
||
GEN9_STANDALONE_ONLY(ms_initState = InitState::Running);
|
||
|
||
#if __DEV
|
||
g_StreamedScripts.ValidateAllScripts();
|
||
#endif
|
||
|
||
scriptAssertf (ms_pXmlTree== NULL, "CTheScripts::Init - XmlNodeTree is not Null");
|
||
ms_pXmlTree = NULL;
|
||
ms_pCurrentXmlTreeNode = NULL;
|
||
ms_bUpdatingScriptThreads = false;
|
||
|
||
//patrol routes
|
||
ms_ScriptPatrol.Init();
|
||
|
||
ms_ScriptsForBrains.Init();
|
||
ms_ScriptBrainDispatcher.Init();
|
||
|
||
#if __DEV
|
||
bDisplayUsedScriptResources = false;
|
||
#endif
|
||
|
||
ms_bPlayerIsOnAMission = false;
|
||
ms_bPlayerIsOnARandomEvent = false;
|
||
ms_bPlayerIsRepeatingAMission = false;
|
||
|
||
ms_NumberOfMiniGamesInProgress = 0;
|
||
|
||
ms_HiddenObjects.Init();
|
||
|
||
ms_bAllowGameToPauseForStreaming = true;
|
||
|
||
ms_bScenarioPedsCanBeGrabbedByScript = false;
|
||
|
||
ms_bCodeRequestedAutosave = false;
|
||
|
||
ms_bKillingAllScriptThreads = false;
|
||
|
||
ms_bProcessingTheScriptsDuringGameInit = false;
|
||
|
||
#if __BANK
|
||
sm_fTimeFadedOut = 0.0f;
|
||
#endif // __BANK
|
||
|
||
#if !__FINAL
|
||
ms_bScriptLaunched = false;
|
||
#endif //!__FINAL
|
||
|
||
sm_ScriptTimer.Reset();
|
||
|
||
SetContentIdOfCurrentUGCMission("");
|
||
|
||
static const int kDefaultItemSetBufferSize = 128; // May want to override this to be much larger through the configuration file, RDR2 needed 2048. Memory per unit should be 4 byets.
|
||
const int itemSetBufferSize = fwConfigManager::GetInstance().GetSizeOfPool(ATSTRINGHASH("ItemSetBuffer", 0x04e2adf9b), kDefaultItemSetBufferSize);
|
||
CItemSetManager::InitClass(itemSetBufferSize);
|
||
|
||
LaunchStartupScript();
|
||
}
|
||
//@@: location CTHESCRIPTS_INIT_INITIALIZE_SCRIPT_SHAPE_TEST_MANAGER
|
||
CScriptShapeTestManager::Init(initMode);
|
||
//@@: location CTHESCRIPTS_INIT_INITIALIZE_MISSION_REPLAY_STATS_INIT
|
||
ms_MissionReplayStats.Init(initMode);
|
||
}
|
||
|
||
void CTheScripts::LaunchStartupScript()
|
||
{
|
||
// if (!bLoadingAPreviouslySavedGame)
|
||
{
|
||
strLocalIndex mainScriptId = strLocalIndex(-1);
|
||
|
||
// Gen9 Landing Page: There is now a pre-startup script that runs before the game session exists.
|
||
// The -startupscript commandline param is delayed until the game session is created,
|
||
// then it is loaded in script by landing_pre_startup.
|
||
#if GEN9_LANDING_PAGE_ENABLED
|
||
const char *pScriptName = "landing_pre_startup";
|
||
#else // GEN9_LANDING_PAGE_ENABLED
|
||
const char *pScriptName = CFileMgr::IsGameInstalled() ? "startup" : "startup_install";
|
||
NOTFINAL_ONLY(PARAM_startupscript.Get(pScriptName));
|
||
#endif // GEN9_LANDING_PAGE_ENABLED
|
||
|
||
#if !__FINAL
|
||
ms_bScriptLaunched = true;
|
||
#endif //!__FINAL
|
||
|
||
mainScriptId = g_StreamedScripts.FindSlot(pScriptName);
|
||
|
||
if(mainScriptId != -1)
|
||
{
|
||
g_StreamedScripts.StreamingRequest(mainScriptId, STRFLAG_DONTDELETE);
|
||
CStreaming::LoadAllRequestedObjects();
|
||
|
||
if (g_StreamedScripts.HasObjectLoaded(mainScriptId))
|
||
{
|
||
#if EXECUTABLE_SCRIPTS
|
||
// Load all of the precompiled controller scripts now. (multiple scripts per PRX/DLL now)
|
||
// We need to do this after we've registered all script commands, and also after all globals
|
||
// have been registered as well.
|
||
// See x:\gta5\script\dev\singleplayer\make_controllers.bat and build_controllers.bat.
|
||
scrProgram::RegisterBinary("controllers");
|
||
#endif // EXECUTABLE_SCRIPTS
|
||
scrThreadId NewScrThreadId = scrThread::CreateThread(g_StreamedScripts.GetProgramId(mainScriptId.Get()), NULL, 0, GtaThread::GetDefaultStackSize());
|
||
|
||
scrThread *pNewScriptThread = scrThread::GetThread(NewScrThreadId);
|
||
if (pNewScriptThread)
|
||
{
|
||
GtaThread *pNewGtaThread = (GtaThread*) pNewScriptThread;
|
||
|
||
pNewGtaThread->Initialise();
|
||
|
||
ms_ScriptHandlerMgr.RegisterScript(*pNewScriptThread);
|
||
|
||
#if __BANK
|
||
if (CScriptDebug::ShouldThisScriptBeDebugged(pNewScriptThread->GetScriptName()))
|
||
{
|
||
GtaThread::AllocateDebuggerForThread(NewScrThreadId);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
g_StreamedScripts.ClearRequiredFlag(mainScriptId.Get(), STRFLAG_DONTDELETE);
|
||
}
|
||
else
|
||
{
|
||
Quitf(ERR_SCR_LAUNCH_1,"CTheScripts::LaunchStartupScript - the %s script has not loaded despite LoadAllRequestedObjects() being called", pScriptName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Quitf(ERR_SCR_LAUNCH_2,"CTheScripts::LaunchStartupScript - failed to find a script with the name %s in the script.rpf", pScriptName);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// name: CTheScripts::Shutdown
|
||
// description:
|
||
void CTheScripts::Shutdown(unsigned shutdownMode)
|
||
{
|
||
if(shutdownMode == SHUTDOWN_CORE)
|
||
{
|
||
GEN9_STANDALONE_ONLY(ms_initState = InitState::Uninitialized);
|
||
|
||
// shutdown script event queues
|
||
GetEventScriptErrorsGroup()->Shutdown();
|
||
GetEventScriptAIGroup()->Shutdown();
|
||
GetEventScriptNetworkGroup()->Shutdown();
|
||
|
||
g_ScriptAudioEntity.StopStream();
|
||
ms_ScriptHandlerMgr.Shutdown();
|
||
g_StreamedScripts.Shutdown();
|
||
CScriptMetadataManager::Shutdown();
|
||
GtaThread::DeallocateThreads();
|
||
scrProgram::ShutdownClass();
|
||
scriptInterface::Shutdown();
|
||
}
|
||
else if(shutdownMode == SHUTDOWN_SESSION)
|
||
{
|
||
// Inform the script engine that it will need to relaunch scripts if the game session is initialised
|
||
GEN9_STANDALONE_ONLY(ms_initState = InitState::Initialized);
|
||
|
||
ms_bKillingAllScriptThreads = true;
|
||
scrThread::KillAllThreads();
|
||
ms_bKillingAllScriptThreads = false;
|
||
|
||
CItemSetManager::ShutdownClass();
|
||
g_ScriptAudioEntity.StopStream();
|
||
g_StreamedScripts.ShutdownLevel();
|
||
ms_HiddenObjects.UndoHiddenObjects();
|
||
|
||
CScriptHud::Shutdown(shutdownMode);
|
||
|
||
ms_scriptOpList.Flush();
|
||
|
||
CGameScriptResource::Shutdown(shutdownMode);
|
||
|
||
#if ENABLE_SCRIPT_GLOBALS_HEAP
|
||
ASSERT_ONLY(scrProgram::AssertGlobalsHeapEmpty();)
|
||
#endif // ENABLE_SCRIPT_GLOBALS_HEAP
|
||
}
|
||
|
||
CScriptShapeTestManager::Shutdown(shutdownMode);
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// FUNCTION : Update
|
||
// PURPOSE : Called by the main update loop.
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
void
|
||
CTheScripts::Update()
|
||
{
|
||
}
|
||
|
||
bool CTheScripts::ShouldBeProcessed()
|
||
{
|
||
if ( (fwTimer::IsGamePaused()) && (fwTimer::ShouldScriptsBePaused()) )
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// Graeme - 14.06.10 - I had to comment this out to allow the scripts to run for one frame during initialisation
|
||
// if(CGame::IsChangingSessionState())
|
||
// { // If the network connection is lost then a message is displayed telling the player this and waiting
|
||
// for A to be pressed. It's probably a bad idea to continue processing the scripts while a session restart is pending.
|
||
// This return will stop any scripts running until the session has ended and a new one has started.
|
||
// return false;
|
||
// }
|
||
|
||
// scripts are only processed when the game is performing a full update/render or HTML is being displayed
|
||
// or the player is on the player settings screen in a network game
|
||
// or the scripts are processing for one frame during the initialisation phase
|
||
// or the Gen9 landing page is displayed before the game session is initialized
|
||
if(!CGame::ShouldDoFullUpdateRender()
|
||
&& !NetworkInterface::IsGameInProgress()
|
||
&& !GetProcessingTheScriptsDuringGameInit()
|
||
GEN9_LANDING_PAGE_ONLY(&& (!CLandingPageArbiter::IsLandingPageActive() || CGame::IsSessionInitialized()))
|
||
)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
ReFrack();
|
||
|
||
// Don't process the scripts with a replay going on.
|
||
#if GTA_REPLAY
|
||
if (CReplayMgr::IsEditModeActive() && !CReplayMgr::ShouldUpdateScripts())
|
||
{
|
||
return false;
|
||
}
|
||
#endif
|
||
|
||
return true;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// FUNCTION : Process
|
||
// PURPOSE : Wrapper for InternalProcess so we can protect script globals from
|
||
// Tampering on PC MP
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
void CTheScripts::Process(void)
|
||
{
|
||
#if RSG_PC && ENABLE_SCRIPT_TAMPER_CHECKER
|
||
//////////////////////////////////////////////////////////////////////////
|
||
// PC only - check for memory-tampering in script globals
|
||
static bool s_bReportedPlayer = false;
|
||
#if !__FINAL
|
||
static bool s_bProtectMemory = true;
|
||
if(PARAM_scriptProtectGlobals.Get())
|
||
{
|
||
s_bProtectMemory = true;
|
||
}
|
||
#endif
|
||
|
||
int page = -1;
|
||
bool isMultiplayer = NetworkInterface::IsAnySessionActive() && NetworkInterface::IsGameInProgress();
|
||
if (
|
||
#if !__FINAL
|
||
s_bProtectMemory &&
|
||
#endif
|
||
!CPauseMenu::IsActive() && CScriptGlobalTamperChecker::CurrentGlobalsDifferFromPreviousFrame(page))
|
||
{
|
||
if ( !s_bReportedPlayer && isMultiplayer )
|
||
{
|
||
s_bReportedPlayer = true;
|
||
RageSecPluginGameReactionObject obj(REACT_GAMESERVER, GENERIC_GAME_ID, 0x20C8C138, 0x611E42B9, 0x23346609);
|
||
rageSecGamePluginManager::GetRageSecGameReactionObjectQueue()->Push(obj);
|
||
}
|
||
}
|
||
|
||
|
||
{ //unchecked scope on PC only
|
||
CScriptGlobalTamperChecker::UncheckedScope uncheckedScope;
|
||
#endif //RSG_PC
|
||
|
||
InternalProcess();
|
||
|
||
#if RSG_PC && ENABLE_SCRIPT_TAMPER_CHECKER
|
||
} // end unchecked scope on PC
|
||
CScriptGlobalTamperChecker::Update();
|
||
#if !__FINAL
|
||
if(s_bProtectMemory)
|
||
#endif
|
||
{
|
||
#if __BANK
|
||
if(CScriptDebug::GetFakeTampering())
|
||
{
|
||
CScriptGlobalTamperChecker::FakeTamper(0);
|
||
}
|
||
#endif //__BANK
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
// FUNCTION : Process
|
||
// PURPOSE : Processes the scripts.
|
||
/////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void CTheScripts::InternalProcess(void)
|
||
{
|
||
|
||
AUTO_HANG_DETECT_CRASH_ZONE;
|
||
ms_ScriptHandlerMgr.Update();
|
||
|
||
#if __BANK
|
||
if (camInterface::IsFadedOut())
|
||
{
|
||
sm_fTimeFadedOut += fwTimer::GetTimeStep();
|
||
}
|
||
else
|
||
{
|
||
sm_fTimeFadedOut = 0.0f;
|
||
}
|
||
|
||
if (DisplayScriptProcessMessagesWhileScreenIsFaded())
|
||
{
|
||
scriptDisplayf("CTheScripts::Process called while screen is faded");
|
||
}
|
||
#endif // __BANK
|
||
|
||
CControlMgr::UpdateVirtualKeyboard();
|
||
|
||
if (!ShouldBeProcessed())
|
||
{
|
||
return;
|
||
}
|
||
|
||
#if GTA_REPLAY
|
||
if(!CReplayMgr::IsReplayDisabled() && !CReplayMgr::IsRecordingEnabled() && !CReplayMgr::ShouldUpdateScripts())
|
||
{
|
||
// update movie mesh manager
|
||
g_movieMeshMgr.Update();
|
||
return;
|
||
}
|
||
#endif //GTA_REPLAY
|
||
|
||
PF_START_TIMEBAR_DETAIL("Script update");
|
||
|
||
NetworkInterface::UpdateBeforeScripts();
|
||
|
||
#if RSG_PC
|
||
NtDll::VerifyProtection();
|
||
Kernel32::VerifyProtection();
|
||
#endif
|
||
|
||
sm_ScriptTimer.Reset();
|
||
|
||
CScriptAreas::Process();
|
||
CScriptCars::Process();
|
||
CScriptPeds::Process();
|
||
CScriptDebug::Process();
|
||
CScriptHud::Process();
|
||
|
||
#if __DEV
|
||
if (bDisplayUsedScriptResources)
|
||
{
|
||
ms_ScriptHandlerMgr.DisplayObjectAndResourceInfo();
|
||
}
|
||
#endif
|
||
|
||
#if __BANK
|
||
ms_ScriptHandlerMgr.DisplayScriptHandlerInfo();
|
||
#endif
|
||
|
||
if (CGameWorld::GetMainPlayerInfo() REPLAY_ONLY(&& CReplayMgr::IsReplayInControlOfWorld() == false))
|
||
{
|
||
CWorldPoints::ScanForScriptTriggerWorldPoints(CGameWorld::FindLocalPlayerCentreOfWorld());
|
||
}
|
||
|
||
ms_ScriptBrainDispatcher.Process();
|
||
|
||
#if __BANK
|
||
if (CScriptDebug::GetOutputScriptDisplayTextCommands())
|
||
{
|
||
scripthudDisplayf("CTheScripts::Process - Start of processing script threads");
|
||
}
|
||
#endif // __BANK
|
||
|
||
scrThread::SetTimeStep(fwTimer::GetTimeStep());
|
||
ms_bUpdatingScriptThreads = true;
|
||
scrThread::UpdateAll(s_InstructionLimit);
|
||
ms_bUpdatingScriptThreads = false;
|
||
|
||
#if __BANK
|
||
if (CScriptDebug::GetOutputScriptDisplayTextCommands())
|
||
{
|
||
scripthudDisplayf("CTheScripts::Process - End of processing script threads");
|
||
}
|
||
#endif // __BANK
|
||
|
||
//Doing this immediately after threads update to minimise time spent with shapetest requests enqueued
|
||
CScriptShapeTestManager::Update();
|
||
|
||
// To free .sco files faster so that they can be used within the Preview folder
|
||
GtaThread::KillAllAbortedScriptThreads();
|
||
|
||
// flush script event queues
|
||
GetEventScriptErrorsGroup()->FlushAllAndMovePending();
|
||
GetEventScriptAIGroup()->FlushAllAndMovePending();
|
||
GetEventScriptNetworkGroup()->FlushAllAndMovePending();
|
||
|
||
// update movie mesh manager
|
||
g_movieMeshMgr.Update();
|
||
|
||
CutSceneManager::GetInstance()->RenderBinkMovieAndUpdateRenderTargets();
|
||
|
||
#if __BANK
|
||
if (DisplayScriptProcessMessagesWhileScreenIsFaded())
|
||
{
|
||
sm_fTimeFadedOut -= 4.0f;
|
||
}
|
||
#endif // __BANK
|
||
|
||
NetworkInterface::UpdateAfterScripts();
|
||
|
||
CAnimSceneManager::Update(kAnimSceneUpdatePostScript);
|
||
}
|
||
|
||
|
||
void CTheScripts::RegisterEntity(CPhysical* pEntity, bool bScriptHostObject, bool bNetworked, bool bNewEntity)
|
||
{
|
||
if (AssertVerify(pEntity) &&
|
||
scriptVerifyf(!pEntity->GetExtension<CScriptEntityExtension>(), "CTheScripts::RegisterEntity - The entity with model %s and PopType %s is already registered as a mission entity", pEntity->GetModelName(), CTheScripts::GetPopTypeName(pEntity->PopTypeGet()) ))
|
||
{
|
||
CScriptEntityExtension* pNewExtension = rage_new CScriptEntityExtension(*pEntity);
|
||
Assert(pEntity->GetExtension<CScriptEntityExtension>());
|
||
|
||
scriptHandler* pScriptHandler = GetCurrentGtaScriptThread()->m_Handler;
|
||
|
||
if (bScriptHostObject && NetworkInterface::IsGameInProgress())
|
||
{
|
||
if (!bNetworked)
|
||
{
|
||
sysStack::PrintStackTrace();
|
||
Displayf("CTheScripts::RegisterEntity - trying to register a non-networked script host entity. Forcing networking.");
|
||
Assertf(0, "CTheScripts::RegisterEntity - trying to register a non-networked script host entity. Forcing networking.");
|
||
bNetworked = true;
|
||
}
|
||
|
||
if (bNetworked && !pEntity->GetNetworkObject())
|
||
{
|
||
sysStack::PrintStackTrace();
|
||
Displayf("CTheScripts::RegisterEntity - trying to register a script host entity with no network object. Forcing client object.");
|
||
Assertf(0, "CTheScripts::RegisterEntity - trying to register a script host entity with no network object. Forcing client object.");
|
||
bScriptHostObject = false;
|
||
bNetworked = false;
|
||
}
|
||
}
|
||
|
||
// cache the networked state so that we know whether to register the object with the network code when a network game starts
|
||
pNewExtension->SetIsNetworked(bNetworked);
|
||
|
||
// all non-networked entities must be client ones as no other machine will know about them
|
||
if (!bNetworked)
|
||
{
|
||
bScriptHostObject = false;
|
||
}
|
||
|
||
if (AssertVerify(pScriptHandler))
|
||
{
|
||
pScriptHandler->RegisterNewScriptObject(static_cast<scriptHandlerObject&>(*pNewExtension), bScriptHostObject, bNetworked);
|
||
|
||
if (pEntity->GetNetworkObject() && pScriptHandler->GetNetworkComponent())
|
||
{
|
||
if (bScriptHostObject)
|
||
{
|
||
static_cast<CGameScriptHandlerNetwork*>(pScriptHandler)->ValidateRegistrationRequest(pEntity, bNewEntity);
|
||
|
||
// host objects should always be cloned on all machines running the script
|
||
pEntity->GetNetworkObject()->SetGlobalFlag(CNetObjGame::GLOBALFLAG_CLONEALWAYS_SCRIPT, true);
|
||
|
||
if (pEntity->GetNetworkObject())
|
||
{
|
||
// update the scope state immediately so that the clone creates will go out a.s.a.p
|
||
NetworkInterface::GetObjectManager().UpdateAllInScopeStateImmediately(pEntity->GetNetworkObject());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
pEntity->ProtectStreamedArchetype();
|
||
}
|
||
}
|
||
|
||
void CTheScripts::UnregisterEntity(CPhysical* pEntity, bool bCleanupScriptState)
|
||
{
|
||
// unregister the ped from its associated script handler.
|
||
CScriptEntityExtension* pExtension = pEntity->GetExtension<CScriptEntityExtension>();
|
||
scriptHandler* pScriptHandler = pExtension ? pExtension->GetScriptHandler() : NULL;
|
||
|
||
if (pExtension && pScriptHandler)
|
||
{
|
||
// don't cleanup the script state of the target object if the object is about to be destroyed
|
||
pExtension->SetCleanupTargetEntity(bCleanupScriptState);
|
||
|
||
// set the no longer needed flag here so that the script handler knows that it needs to clean up the script info for the entity
|
||
pExtension->SetNoLongerNeeded(true);
|
||
|
||
pScriptHandler->UnregisterScriptObject(*pExtension);
|
||
|
||
pEntity->UnprotectStreamedArchetype();
|
||
}
|
||
|
||
// Graeme - the correct thing to do would be to delete the script guid for this entity here so that the entity can no longer be referenced by script
|
||
// A few scripts are relying on being able to make a temp copy of an entityId, mark the entity as no longer needed and then call a few extra commands through the copied entityId
|
||
// This wouldn't be possible if the line below was uncommented
|
||
// fwScriptGuid::DeleteGuid(*pEntity);
|
||
}
|
||
|
||
CEntity** CTheScripts::GetAllScriptEntities(u32& numEntities)
|
||
{
|
||
const u32 maxNumberOfScriptEntities = 700;
|
||
static CEntity* entities[maxNumberOfScriptEntities];
|
||
|
||
DEV_ONLY(memset(entities, 0, sizeof(entities)));
|
||
|
||
scriptAssertf(maxNumberOfScriptEntities == (u32) CScriptEntityExtension::GetPool()->GetSize(), "CTheScripts::GetAllScriptEntities - maxNumberOfScriptEntities is %u. Change it to match the size of the CScriptEntityExtension pool which is defined in gameconfig.xml to be %d",
|
||
maxNumberOfScriptEntities, CScriptEntityExtension::GetPool()->GetSize());
|
||
|
||
numEntities = ms_ScriptHandlerMgr.GetAllScriptHandlerEntities(entities, maxNumberOfScriptEntities);
|
||
|
||
return entities;
|
||
}
|
||
|
||
bool CTheScripts::GetPlayerIsOnAMission(void)
|
||
{
|
||
if (ms_bPlayerIsOnAMission)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool CTheScripts::IsPlayerPlaying(CPed *pPlayerPed)
|
||
{
|
||
if (scriptVerifyf(pPlayerPed, "CTheScripts::IsPlayerPlaying - ped pointer is NULL"))
|
||
{
|
||
CPlayerInfo *pPlayerInfo = pPlayerPed->GetPlayerInfo();
|
||
if (scriptVerifyf(pPlayerInfo, "CTheScripts::IsPlayerPlaying - ped doesn't have PlayerInfo"))
|
||
{
|
||
if (pPlayerInfo->IsRestartingAfterDeath() || pPlayerPed->IsInjured()
|
||
|| pPlayerInfo->IsRestartingAfterArrest())
|
||
{
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
#if __DEV
|
||
void CTheScripts::ClearAllEntityCheckedForDeadFlags(void)
|
||
{
|
||
CPed::Pool *pedpool = CPed::GetPool();
|
||
CPed *pPed;
|
||
CVehicle::Pool *vehpool = CVehicle::GetPool();
|
||
CVehicle *pVehicle;
|
||
s32 i;
|
||
|
||
i = (s32) pedpool->GetSize();
|
||
|
||
while (i--)
|
||
{
|
||
pPed = pedpool->GetSlot(i);
|
||
|
||
if (pPed) // && !pPed->IsPlayer())
|
||
{
|
||
pPed->m_nDEflags.bCheckedForDead = FALSE;
|
||
}
|
||
}
|
||
|
||
i = (s32) vehpool->GetSize();
|
||
|
||
while (i--)
|
||
{
|
||
pVehicle = vehpool->GetSlot(i);
|
||
|
||
if (pVehicle)
|
||
{
|
||
pVehicle->m_nDEflags.bCheckedForDead = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
#endif // __DEV
|
||
|
||
|
||
GtaThread *CTheScripts::GetCurrentGtaScriptThread(void)
|
||
{
|
||
return static_cast<GtaThread *>(scrThread::GetActiveThread());
|
||
}
|
||
|
||
CGameScriptHandler *CTheScripts::GetCurrentGtaScriptHandler(void)
|
||
{
|
||
return (scrThread::GetActiveThread() ? static_cast<GtaThread *>(scrThread::GetActiveThread())->m_Handler : NULL);
|
||
}
|
||
|
||
CGameScriptHandlerNetwork *CTheScripts::GetCurrentGtaScriptHandlerNetwork(void)
|
||
{
|
||
CGameScriptHandler *pHandler = GetCurrentGtaScriptHandler();
|
||
|
||
if (pHandler && pHandler->RequiresANetworkComponent())
|
||
{
|
||
return static_cast<CGameScriptHandlerNetwork *>(pHandler);
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
void CTheScripts::PrioritizeRequestsFromMissionScript(s32 &streamingFlags)
|
||
{
|
||
if (!GetCurrentGtaScriptThread() || !GetCurrentGtaScriptThread()->m_bIsHighPrio)
|
||
return;
|
||
|
||
if (GetCurrentGtaScriptThread()->IsThisAMissionScript || GetCurrentGtaScriptThread()->GetIsARandomEventScript() || GetCurrentGtaScriptThread()->GetIsATriggerScript())
|
||
{
|
||
streamingFlags |= STRFLAG_PRIORITY_LOAD;
|
||
}
|
||
}
|
||
|
||
u32 CTheScripts::GetCurrentScriptHash(void)
|
||
{
|
||
const u32 noScript = 0;
|
||
if (ms_bUpdatingScriptThreads)
|
||
{
|
||
return scrThread::GetActiveThread()->GetScriptNameHash();
|
||
}
|
||
else
|
||
{
|
||
return noScript;
|
||
}
|
||
}
|
||
|
||
const char *CTheScripts::GetCurrentScriptName(void)
|
||
{
|
||
const char* noScript = "";
|
||
if (ms_bUpdatingScriptThreads)
|
||
{
|
||
return scrThread::GetActiveThread()->GetScriptName();
|
||
}
|
||
else
|
||
{
|
||
return noScript;
|
||
}
|
||
}
|
||
|
||
#if !__NO_OUTPUT
|
||
const char *CTheScripts::GetCurrentScriptNameAndProgramCounter(void)
|
||
{
|
||
static char text[256];
|
||
|
||
if (ms_bUpdatingScriptThreads)
|
||
{
|
||
sprintf(text, "SCRIPT: Script Name = %s : Program Counter = %d", GetCurrentScriptName(), GetCurrentGtaScriptThread()->GetThreadPC() );
|
||
}
|
||
else
|
||
{
|
||
sprintf(text, " ");
|
||
}
|
||
|
||
return text;
|
||
}
|
||
#endif // !__NO_OUTPUT
|
||
|
||
|
||
void CTheScripts::SetContentIdOfCurrentUGCMission(const char *pContentIdString)
|
||
{
|
||
if (pContentIdString == NULL)
|
||
{
|
||
scriptAssertf(0, "CTheScripts::SetContentIdOfCurrentUGCMission called with a NULL string so setting the string to empty");
|
||
pContentIdString = "";
|
||
}
|
||
|
||
safecpy(ms_ContentIdOfCurrentUGCMission, pContentIdString, NELEM(ms_ContentIdOfCurrentUGCMission));
|
||
}
|
||
|
||
// ********************* CMissionReplayStats **************************
|
||
void CMissionReplayStats::Init(unsigned initMode)
|
||
{
|
||
// Don't clear the structure in INIT_SESSION
|
||
if(initMode == INIT_CORE)
|
||
{
|
||
ClearReplayStatsStructure();
|
||
}
|
||
}
|
||
|
||
// When a Replay Mission is passed
|
||
void CMissionReplayStats::BeginReplayStatsStructure(s32 missionId, s32 missionType)
|
||
{
|
||
if (scriptVerifyf(m_bStatsHaveBeenStored == false, "CMissionReplayStats::BeginReplayStatsStructure - stats have already been stored"))
|
||
{
|
||
if (scriptVerifyf(m_bConstructingStructureOfStats == false, "CMissionReplayStats::BeginReplayStatsStructure - structure of stats is already being constructed"))
|
||
{
|
||
m_bConstructingStructureOfStats = true;
|
||
m_nMissionId = missionId;
|
||
m_nMissionType = missionType;
|
||
|
||
m_ArrayOfMissionStats.Reset();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CMissionReplayStats::AddStatValueToReplayStatsStructure(s32 valueOfStat)
|
||
{
|
||
if (scriptVerifyf(m_bConstructingStructureOfStats, "CMissionReplayStats::AddStatValueToReplayStatsStructure - structure of stats is not being constructed. Check that BEGIN_REPLAY_STATS has been called first"))
|
||
{
|
||
if (scriptVerifyf(m_bStatsHaveBeenStored == false, "CMissionReplayStats::AddStatValueToReplayStatsStructure - stats have already been stored"))
|
||
{
|
||
m_ArrayOfMissionStats.PushAndGrow(valueOfStat);
|
||
}
|
||
}
|
||
}
|
||
|
||
void CMissionReplayStats::EndReplayStatsStructure()
|
||
{
|
||
if (scriptVerifyf(m_bConstructingStructureOfStats, "CMissionReplayStats::EndReplayStatsStructure - structure of stats is not being constructed. Check that BEGIN_REPLAY_STATS has been called first"))
|
||
{
|
||
if (scriptVerifyf(m_bStatsHaveBeenStored == false, "CMissionReplayStats::EndReplayStatsStructure - stats have already been stored"))
|
||
{
|
||
m_bStatsHaveBeenStored = true;
|
||
m_bConstructingStructureOfStats = false;
|
||
}
|
||
}
|
||
}
|
||
// End of "When a Replay Mission is passed"
|
||
|
||
// When a Load happens and the script detects that it<69>s a Replay save file
|
||
s32 CMissionReplayStats::GetNumberOfMissionStats()
|
||
{
|
||
if (scriptVerifyf(m_bStatsHaveBeenStored, "CMissionReplayStats::GetNumberOfMissionStats - stats haven't been stored"))
|
||
{
|
||
return m_ArrayOfMissionStats.GetCount();
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
s32 CMissionReplayStats::GetStatValueAtIndex(s32 arrayIndex)
|
||
{
|
||
if (scriptVerifyf(m_bStatsHaveBeenStored, "CMissionReplayStats::GetStatValueAtIndex - stats haven't been stored"))
|
||
{
|
||
if (scriptVerifyf( (arrayIndex >= 0) && (arrayIndex < m_ArrayOfMissionStats.GetCount()), "CMissionReplayStats::GetStatValueAtIndex - arrayIndex %d is out of range 0 to %d", arrayIndex, m_ArrayOfMissionStats.GetCount()))
|
||
{
|
||
return m_ArrayOfMissionStats[arrayIndex];
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
void CMissionReplayStats::ClearReplayStatsStructure()
|
||
{
|
||
|
||
m_bStatsHaveBeenStored = false;
|
||
m_bConstructingStructureOfStats = false;
|
||
m_nMissionId = 0;
|
||
m_nMissionType = 0;
|
||
|
||
m_ArrayOfMissionStats.Reset();
|
||
}
|
||
// End of "When a Load happens and the script detects that it<69>s a Replay save file"
|
||
|
||
|
||
|
||
// ********************* CHiddenObjects **************************
|
||
void CHiddenObjects::Init()
|
||
{
|
||
m_MapOfHiddenObjects.Reset();
|
||
}
|
||
|
||
|
||
#if !__NO_OUTPUT
|
||
void CHiddenObjects::DisplayInteriorDetails(fwInteriorLocation &interiorLoc)
|
||
{
|
||
if (interiorLoc.IsValid())
|
||
{
|
||
scriptDisplayf("CHiddenObjects::DisplayInteriorDetails - interiorLoc is valid");
|
||
|
||
scriptDisplayf("CHiddenObjects::DisplayInteriorDetails - interior proxy index is %d", interiorLoc.GetInteriorProxyIndex());
|
||
|
||
if (interiorLoc.IsAttachedToRoom())
|
||
{
|
||
scriptDisplayf("CHiddenObjects::DisplayInteriorDetails - interiorLoc is attached to room. Room index is %d", interiorLoc.GetRoomIndex());
|
||
}
|
||
|
||
if (interiorLoc.IsAttachedToPortal())
|
||
{
|
||
scriptDisplayf("CHiddenObjects::DisplayInteriorDetails - interiorLoc is attached to portal. Portal index is %d. PortalToExterior=%s", interiorLoc.GetPortalIndex(), interiorLoc.IsPortalToExterior()?"true":"false");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
scriptDisplayf("CHiddenObjects::DisplayInteriorDetails - interiorLoc is not valid");
|
||
}
|
||
}
|
||
#endif // !__NO_OUTPUT
|
||
|
||
void CHiddenObjects::AddToHiddenObjectMap(s32 ScriptGUIDOfEntity, spdSphere &SearchVolume, s32 ModelHash,
|
||
CDummyObject *pDummyObj, fwInteriorLocation DummyInteriorLocation, s32 IplIndex)
|
||
{
|
||
if (m_MapOfHiddenObjects.Access(ScriptGUIDOfEntity) == NULL)
|
||
{
|
||
hidden_object_struct HiddenObjStruct;
|
||
HiddenObjStruct.m_SearchVolume = SearchVolume;
|
||
HiddenObjStruct.m_ModelHash = ModelHash;
|
||
|
||
#if !__NO_OUTPUT
|
||
fwModelId modelId;
|
||
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfoFromHashKey(static_cast< u32 >( ModelHash ), &modelId);
|
||
|
||
if (scriptVerifyf(modelId.IsValid(), "CHiddenObjects::AddToHiddenObjectMap - %d (signed) %u (unsigned) is not a valid model hash", ModelHash, (u32) ModelHash))
|
||
{
|
||
Vec3V SearchPos = SearchVolume.GetCenter();
|
||
scriptDisplayf("CHiddenObjects::AddToHiddenObjectMap - called for %s at %f %f %f", pModelInfo->GetModelName(), SearchPos.GetXf(), SearchPos.GetYf(), SearchPos.GetZf());
|
||
}
|
||
#endif // !__NO_OUTPUT
|
||
|
||
HiddenObjStruct.m_pRelatedDummyForObjectGrabbedFromTheWorld = pDummyObj;
|
||
HiddenObjStruct.m_InteriorLocationOfRelatedDummyForObjectGrabbedFromTheWorld = DummyInteriorLocation;
|
||
HiddenObjStruct.m_IplIndexOfObjectGrabbedFromTheWorld = IplIndex;
|
||
|
||
#if !__NO_OUTPUT
|
||
scriptDisplayf("CHiddenObjects::AddToHiddenObjectMap - interior location details are");
|
||
DisplayInteriorDetails(DummyInteriorLocation);
|
||
#endif // !__NO_OUTPUT
|
||
|
||
m_MapOfHiddenObjects.Insert(ScriptGUIDOfEntity, HiddenObjStruct);
|
||
}
|
||
|
||
g_MapChangeMgr.Add((u32) ModelHash, (u32) ModelHash, SearchVolume, true, CMapChange::TYPE_HIDE, true, true);
|
||
}
|
||
|
||
|
||
void CHiddenObjects::ReregisterInHiddenObjectMap(s32 oldScriptGUIDOfEntity, s32 newScriptGUIDOfEntity)
|
||
{
|
||
if (oldScriptGUIDOfEntity != newScriptGUIDOfEntity)
|
||
{
|
||
// Get entry for old GUID
|
||
hidden_object_struct *pHideDataForThisEntity = m_MapOfHiddenObjects.Access(oldScriptGUIDOfEntity);
|
||
if (pHideDataForThisEntity)
|
||
{
|
||
hidden_object_struct HiddenObjStruct = *pHideDataForThisEntity;
|
||
|
||
// Remove entry for old GUID
|
||
m_MapOfHiddenObjects.Delete(oldScriptGUIDOfEntity);
|
||
|
||
if (scriptVerifyf(m_MapOfHiddenObjects.Access(newScriptGUIDOfEntity) == NULL,
|
||
"CHiddenObjects::ReregisterInHiddenObjectMap - MapOfHiddenObjects contains data for old GUID %d, but we didn't expect it to also contain data for the new GUID %d", oldScriptGUIDOfEntity, newScriptGUIDOfEntity))
|
||
{
|
||
#if !__NO_OUTPUT
|
||
fwModelId modelId;
|
||
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfoFromHashKey(static_cast< u32 >( HiddenObjStruct.m_ModelHash ), &modelId);
|
||
|
||
if (scriptVerifyf(modelId.IsValid(), "CHiddenObjects::ReregisterInHiddenObjectMap - %d (signed) %u (unsigned) is not a valid model hash", HiddenObjStruct.m_ModelHash, (u32) HiddenObjStruct.m_ModelHash))
|
||
{
|
||
Vec3V SearchPos = HiddenObjStruct.m_SearchVolume.GetCenter();
|
||
scriptDisplayf("CHiddenObjects::ReregisterInHiddenObjectMap - called for %s at %f %f %f (Old GUID=%d, New GUID=%d)",
|
||
pModelInfo->GetModelName(), SearchPos.GetXf(), SearchPos.GetYf(), SearchPos.GetZf(),
|
||
oldScriptGUIDOfEntity, newScriptGUIDOfEntity);
|
||
}
|
||
|
||
scriptDisplayf("CHiddenObjects::ReregisterInHiddenObjectMap - interior location details are");
|
||
DisplayInteriorDetails(HiddenObjStruct.m_InteriorLocationOfRelatedDummyForObjectGrabbedFromTheWorld);
|
||
#endif // !__NO_OUTPUT
|
||
|
||
// Add entry for new GUID
|
||
m_MapOfHiddenObjects.Insert(newScriptGUIDOfEntity, HiddenObjStruct);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
bool CHiddenObjects::RemoveFromHiddenObjectMap(s32 ScriptGUIDOfEntity, bool bHandleRelatedDummy)
|
||
{
|
||
bool bReturnValue = false;
|
||
|
||
hidden_object_struct *pHideDataForThisEntity = m_MapOfHiddenObjects.Access(ScriptGUIDOfEntity);
|
||
if (pHideDataForThisEntity)
|
||
{
|
||
g_MapChangeMgr.Remove(pHideDataForThisEntity->m_ModelHash, pHideDataForThisEntity->m_ModelHash,
|
||
pHideDataForThisEntity->m_SearchVolume, CMapChange::TYPE_HIDE, false);
|
||
|
||
CObject *pObject = CTheScripts::GetEntityToModifyFromGUID<CObject>(ScriptGUIDOfEntity, 0);
|
||
if (bHandleRelatedDummy && pObject)
|
||
{
|
||
#if !__NO_OUTPUT
|
||
Vec3V SearchPos = pHideDataForThisEntity->m_SearchVolume.GetCenter();
|
||
scriptDisplayf("CHiddenObjects::RemoveFromHiddenObjectMap has been called for %s at %f %f %f", pObject->GetModelName(), SearchPos.GetXf(), SearchPos.GetYf(), SearchPos.GetZf());
|
||
#endif // !__NO_OUTPUT
|
||
|
||
if (!pObject->GetIsRetainedByInteriorProxy())
|
||
{ // If the object is on a retained list then that means the interior is shut down so skip the following code
|
||
// and just make the object ENTITY_OWNEDBY_TEMP
|
||
CDummyObject *pRelatedDummy = pHideDataForThisEntity->m_pRelatedDummyForObjectGrabbedFromTheWorld;
|
||
fwInteriorLocation RelatedDummyLocation = pHideDataForThisEntity->m_InteriorLocationOfRelatedDummyForObjectGrabbedFromTheWorld;
|
||
s32 IplIndex = pHideDataForThisEntity->m_IplIndexOfObjectGrabbedFromTheWorld;
|
||
|
||
if (!pRelatedDummy)
|
||
{
|
||
scriptDisplayf("CHiddenObjects::RemoveFromHiddenObjectMap - pointer to related dummy for object %s has been lost so start a world search", pObject->GetModelName());
|
||
pRelatedDummy = FindClosestMatchingDummy(pHideDataForThisEntity, pObject);
|
||
}
|
||
|
||
if (pRelatedDummy)
|
||
{
|
||
pObject->SetIplIndex(IplIndex);
|
||
|
||
pObject->SetRelatedDummy(pRelatedDummy, RelatedDummyLocation);
|
||
// Can I just call CDummyObject::Disable() and let CObjectPopulation::ManageObject decide whether the object
|
||
// should be swapped to the dummy?
|
||
pRelatedDummy->Disable();
|
||
|
||
scriptDisplayf("CHiddenObjects::RemoveFromHiddenObjectMap - related dummy for object %s has been set up", pObject->GetModelName());
|
||
|
||
bReturnValue = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
scriptDisplayf("CHiddenObjects::RemoveFromHiddenObjectMap - object %s is on a retained list so skipping the code to re-establish a connection with the related dummy", pObject->GetModelName());
|
||
}
|
||
}
|
||
|
||
m_MapOfHiddenObjects.Delete(ScriptGUIDOfEntity);
|
||
}
|
||
|
||
return bReturnValue;
|
||
}
|
||
|
||
void CHiddenObjects::UndoHiddenObjects()
|
||
{
|
||
scriptAssertf(m_MapOfHiddenObjects.GetNumUsed() == 0, "CHiddenObjects::UndoHiddenObjects - expected all hidden objects to have been dealt with already during Shutdown Session");
|
||
|
||
// If any objects haven't already been unhidden then do that now
|
||
atMap<s32, hidden_object_struct>::Iterator mapIterator = m_MapOfHiddenObjects.CreateIterator();
|
||
while (!mapIterator.AtEnd())
|
||
{
|
||
s32 ScriptGUID = mapIterator.GetKey();
|
||
// Can I assume that all CObjects will be deleted in Shutdown Session
|
||
// and that UndoHiddenObjects() will only be called during Shutdown Session
|
||
RemoveFromHiddenObjectMap(ScriptGUID, false);
|
||
mapIterator.Start();
|
||
}
|
||
}
|
||
|
||
|
||
struct ClosestDummyObjectStruct
|
||
{
|
||
CEntity *m_pClosestDummyObject;
|
||
|
||
u32 m_ModelHash;
|
||
fwInteriorLocation m_InteriorLocation;
|
||
s32 m_IplIndex;
|
||
|
||
float m_fClosestDistanceSquared;
|
||
Vec3V m_vCoordToCalculateDistanceFrom;
|
||
};
|
||
|
||
|
||
bool GetClosestDummyObjectCB(CEntity* pEntity, void* data)
|
||
{
|
||
if (scriptVerifyf(pEntity, "GetClosestDummyObjectCB - entity pointer is NULL"))
|
||
{
|
||
if (scriptVerifyf(data, "GetClosestDummyObjectCB - data pointer is NULL"))
|
||
{
|
||
ClosestDummyObjectStruct* pClosestDummyObjectData = reinterpret_cast<ClosestDummyObjectStruct*>(data);
|
||
|
||
if(pEntity->GetIsTypeDummyObject())
|
||
{
|
||
if (pEntity->GetBaseModelInfo()->GetModelNameHash() == pClosestDummyObjectData->m_ModelHash)
|
||
{
|
||
if (pEntity->GetIplIndex() == pClosestDummyObjectData->m_IplIndex)
|
||
{
|
||
if (pEntity->GetInteriorLocation().IsSameLocation(pClosestDummyObjectData->m_InteriorLocation))
|
||
{
|
||
//Get the distance between the centre of the locate and the entities position
|
||
Vec3V DiffVector = pEntity->GetTransform().GetPosition() - pClosestDummyObjectData->m_vCoordToCalculateDistanceFrom;
|
||
|
||
const float ObjDistanceSquared = MagSquared(DiffVector).Getf();
|
||
|
||
if (ObjDistanceSquared < pClosestDummyObjectData->m_fClosestDistanceSquared)
|
||
{
|
||
pClosestDummyObjectData->m_pClosestDummyObject = pEntity;
|
||
pClosestDummyObjectData->m_fClosestDistanceSquared = ObjDistanceSquared;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
// Debug function to print reason for failure of FindClosestMatchingDummy
|
||
void CHiddenObjects::DisplayFailReason(const char* ASSERT_ONLY(pFailReason), const hidden_object_struct* ASSERT_ONLY(pHideData), const CObject* ASSERT_ONLY(pObject))
|
||
{
|
||
#if __ASSERT
|
||
Vector3 vObjectCoors(0.0f, 0.0f, 0.0f);
|
||
const char *pObjectName = "Unknown Object";
|
||
if (pObject)
|
||
{
|
||
vObjectCoors = VEC3V_TO_VECTOR3(pObject->GetTransform().GetPosition());
|
||
pObjectName = pObject->GetModelName();
|
||
}
|
||
Vec3V SearchPos = pHideData->m_SearchVolume.GetCenter();
|
||
|
||
scriptAssertf(0,
|
||
"%s Object Name = %s, Object Pos = %f %f %f, Original Search Pos = %f %f %f",
|
||
pFailReason, pObjectName, vObjectCoors.GetX(), vObjectCoors.GetY(), vObjectCoors.GetZ(),
|
||
SearchPos.GetXf(), SearchPos.GetYf(), SearchPos.GetZf());
|
||
#endif // __ASSERT
|
||
}
|
||
|
||
CDummyObject *CHiddenObjects::FindClosestMatchingDummy(hidden_object_struct *pHideData, const CObject* pObject)
|
||
{
|
||
CDummyObject *pDummyObject = NULL;
|
||
|
||
fwInteriorLocation InteriorLoc = pHideData->m_InteriorLocationOfRelatedDummyForObjectGrabbedFromTheWorld;
|
||
|
||
bool bInteriorIsLoaded = false;
|
||
bool bExteriorIsLoaded = false;
|
||
if (InteriorLoc.IsValid())
|
||
{
|
||
#if !__NO_OUTPUT
|
||
scriptDisplayf("CHiddenObjects::FindClosestMatchingDummy - interior location details are");
|
||
DisplayInteriorDetails(InteriorLoc);
|
||
#endif // !__NO_OUTPUT
|
||
|
||
CInteriorProxy *pInteriorProxy = CInteriorProxy::GetFromLocation(InteriorLoc);
|
||
if (pInteriorProxy)
|
||
{
|
||
if (pInteriorProxy->GetCurrentState() >= CInteriorProxy::PS_FULL)
|
||
{
|
||
bInteriorIsLoaded = true;
|
||
scriptDisplayf("CHiddenObjects::FindClosestMatchingDummy - interior %d is instanced", InteriorLoc.GetInteriorProxyIndex());
|
||
}
|
||
else
|
||
{
|
||
scriptDisplayf("CHiddenObjects::FindClosestMatchingDummy - current state of interior proxy is %u", pInteriorProxy->GetCurrentState());
|
||
|
||
scriptDisplayf("---");
|
||
scriptDisplayf("interior & object dump...\n");
|
||
scriptDisplayf("interior : %s, room : %d\n",pInteriorProxy->GetModelName(),InteriorLoc.GetRoomIndex());
|
||
CDebug::DumpEntity(pObject);
|
||
|
||
// this assert isn't a real problem - object may have been pushed into exterior
|
||
//DisplayFailReason("CHiddenObjects::FindClosestMatchingDummy - expected interior to be instanced at this stage. If this was not the case, we should have earlied-out due to the CObject being retained.", pHideData, pObject);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DisplayFailReason("CHiddenObjects::FindClosestMatchingDummy - pInteriorProxy is NULL.", pHideData, pObject);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// fwMapDataDef* pDef = fwMapDataStore::GetStore().GetSlot(pHideData->m_IplIndexOfObjectGrabbedFromTheWorld);
|
||
// if (pDef && pDef->IsLoaded())
|
||
if ( fwMapDataStore::GetStore().HasObjectLoaded(strLocalIndex(pHideData->m_IplIndexOfObjectGrabbedFromTheWorld)) )
|
||
{
|
||
bExteriorIsLoaded = true;
|
||
scriptDisplayf("CHiddenObjects::FindClosestMatchingDummy - ipl %d is loaded", pHideData->m_IplIndexOfObjectGrabbedFromTheWorld);
|
||
}
|
||
}
|
||
|
||
if (bInteriorIsLoaded || bExteriorIsLoaded)
|
||
{
|
||
ClosestDummyObjectStruct searchData;
|
||
searchData.m_pClosestDummyObject = NULL;
|
||
|
||
searchData.m_ModelHash = (u32) pHideData->m_ModelHash;
|
||
searchData.m_InteriorLocation = InteriorLoc;
|
||
searchData.m_IplIndex = pHideData->m_IplIndexOfObjectGrabbedFromTheWorld;
|
||
|
||
searchData.m_fClosestDistanceSquared = pHideData->m_SearchVolume.GetRadiusSquaredf() * 4.0f; // set this to larger than the scan range (remember it's squared distance)
|
||
searchData.m_vCoordToCalculateDistanceFrom = pHideData->m_SearchVolume.GetCenter();
|
||
|
||
SEARCH_LOCATION_FLAGS SearchFlags = SEARCH_LOCATION_EXTERIORS; // Search exteriors only
|
||
if (bInteriorIsLoaded)
|
||
{
|
||
SearchFlags = SEARCH_LOCATION_INTERIORS; // Search interiors only
|
||
}
|
||
|
||
fwIsSphereIntersecting searchSphere(pHideData->m_SearchVolume);
|
||
CGameWorld::ForAllEntitiesIntersecting(&searchSphere, GetClosestDummyObjectCB, (void*) &searchData,
|
||
ENTITY_TYPE_MASK_DUMMY_OBJECT, SearchFlags,
|
||
SEARCH_LODTYPE_HIGHDETAIL, SEARCH_OPTION_NONE, WORLDREP_SEARCHMODULE_SCRIPT);
|
||
|
||
if (searchData.m_pClosestDummyObject)
|
||
{
|
||
if (scriptVerifyf(searchData.m_pClosestDummyObject->GetIsTypeDummyObject(), "CHiddenObjects::FindClosestMatchingDummy - expected entity to be a dummy object"))
|
||
{
|
||
pDummyObject = static_cast<CDummyObject*>(searchData.m_pClosestDummyObject);
|
||
}
|
||
}
|
||
}
|
||
|
||
return pDummyObject;
|
||
}
|
||
// ********************* End of CHiddenObjects **************************
|
||
|
||
#if __ASSERT
|
||
bool CTheScripts::IsValidGlobalVariable(int *AddressToTest)
|
||
{
|
||
for (int i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
scrValue *pLow_addr = scrProgram::GetGlobals(i);
|
||
scrValue *pHigh_addr = scrProgram::GetGlobals(i) + (scrProgram::GetGlobalSize(i)); // 4 *
|
||
if ( (pLow_addr <= (scrValue *) AddressToTest) && ((scrValue *) AddressToTest < pHigh_addr) )
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
void CTheScripts::DoEntityModifyChecks(const fwEntity* pEntity, unsigned assertFlags)
|
||
{
|
||
if (scrThread::GetCurrentCmdName())
|
||
{
|
||
if (assertFlags & GUID_ASSERT_FLAG_ENTITY_EXISTS)
|
||
{
|
||
scriptAssertf(pEntity, "%s: %s - Entity doesn't exist", GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName());
|
||
}
|
||
|
||
if (pEntity && (pEntity->GetType() == ENTITY_TYPE_VEHICLE || pEntity->GetType() == ENTITY_TYPE_PED || pEntity->GetType() == ENTITY_TYPE_OBJECT))
|
||
{
|
||
const CPhysical* pPhysical = static_cast<const CPhysical*>(pEntity);
|
||
|
||
if (assertFlags & GUID_ASSERT_FLAG_DEAD_CHECK && pEntity->GetType() != ENTITY_TYPE_OBJECT)
|
||
{
|
||
scriptAssertf (pPhysical->m_nDEflags.bCheckedForDead == TRUE, "%s: %s - Check entity is alive this frame", GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName());
|
||
}
|
||
|
||
if (assertFlags & GUID_ASSERT_FLAG_NOT_CLONE)
|
||
{
|
||
if (pPhysical->IsNetworkClone() || (pPhysical->GetNetworkObject() && pPhysical->GetNetworkObject()->IsPendingOwnerChange()))
|
||
{
|
||
scriptAssertf (0, "%s: %s - Cannot call this command on an entity (%s) owned by another machine! (Clone: %s, migrating: %s)", GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName(), pPhysical->GetNetworkObject()->GetLogName(), pPhysical->IsNetworkClone() ? "true" : "false", pPhysical->GetNetworkObject()->IsPendingOwnerChange() ? "true" : "false");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif // __ASSERT
|
||
|
||
|
||
#if __BANK
|
||
|
||
const char *CTheScripts::GetPopTypeName(ePopType PopType)
|
||
{
|
||
switch (PopType)
|
||
{
|
||
case POPTYPE_UNKNOWN :
|
||
return "POPTYPE_UNKNOWN";
|
||
case POPTYPE_RANDOM_PERMANENT :
|
||
return "POPTYPE_RANDOM_PERMANENT";
|
||
case POPTYPE_RANDOM_PARKED :
|
||
return "POPTYPE_RANDOM_PARKED";
|
||
case POPTYPE_RANDOM_PATROL :
|
||
return "POPTYPE_RANDOM_PATROL";
|
||
case POPTYPE_RANDOM_SCENARIO :
|
||
return "POPTYPE_RANDOM_SCENARIO";
|
||
case POPTYPE_RANDOM_AMBIENT :
|
||
return "POPTYPE_RANDOM_AMBIENT";
|
||
case POPTYPE_PERMANENT :
|
||
return "POPTYPE_PERMANENT";
|
||
case POPTYPE_MISSION :
|
||
return "POPTYPE_MISSION";
|
||
case POPTYPE_REPLAY :
|
||
return "POPTYPE_REPLAY";
|
||
case POPTYPE_TOOL :
|
||
return "POPTYPE_TOOL";
|
||
case POPTYPE_CACHE :
|
||
return "POPTYPE_CACHE";
|
||
case NUM_POPTYPES :
|
||
return "NUM_POPTYPES";
|
||
}
|
||
|
||
return "Unknown PopType";
|
||
}
|
||
|
||
#endif // __BANK
|
||
|
||
fwExtensibleBase* CTheScripts::GetExtensibleBaseToModifyFromGUID(int guid, const char* ASSERT_ONLY(commandName), unsigned ASSERT_ONLY(assertFlags))
|
||
{
|
||
fwExtensibleBase* pBase = fwScriptGuid::FromGuid<fwExtensibleBase>(guid);
|
||
|
||
#if __ASSERT
|
||
if (commandName)
|
||
{
|
||
if (assertFlags & GUID_ASSERT_FLAG_ENTITY_EXISTS)
|
||
{
|
||
scriptAssertf(pBase, "%s: %s - Object doesn't exist", GetCurrentScriptNameAndProgramCounter(), commandName);
|
||
}
|
||
}
|
||
#endif // __ASSERT
|
||
|
||
return pBase;
|
||
}
|
||
|
||
CItemSet* CTheScripts::GetItemSetToModifyFromGUID(int guid, const char* ASSERT_ONLY(commandName), unsigned ASSERT_ONLY(assertFlags))
|
||
{
|
||
CItemSet* pItemSet = fwScriptGuid::FromGuid<CItemSet>(guid);
|
||
|
||
#if __ASSERT
|
||
if (commandName)
|
||
{
|
||
if (assertFlags & GUID_ASSERT_FLAG_ENTITY_EXISTS)
|
||
{
|
||
scriptAssertf(pItemSet, "%s: %s - Item set doesn't exist", GetCurrentScriptNameAndProgramCounter(), commandName);
|
||
}
|
||
}
|
||
#endif // __ASSERT
|
||
|
||
return pItemSet;
|
||
}
|
||
|
||
CScriptedCoverPoint* CTheScripts::GetScriptedCoverPointToModifyFromGUID(int guid, const char* ASSERT_ONLY(commandName), unsigned ASSERT_ONLY(assertFlags))
|
||
{
|
||
CScriptedCoverPoint* pScriptedCoverPoint = fwScriptGuid::FromGuid<CScriptedCoverPoint>(guid);
|
||
|
||
#if __ASSERT
|
||
if (commandName)
|
||
{
|
||
if (assertFlags & GUID_ASSERT_FLAG_ENTITY_EXISTS)
|
||
{
|
||
scriptAssertf(pScriptedCoverPoint, "%s: %s - Scripted coverpoint doesn't exist", GetCurrentScriptNameAndProgramCounter(), commandName);
|
||
}
|
||
}
|
||
#endif // __ASSERT
|
||
|
||
return pScriptedCoverPoint;
|
||
}
|
||
|
||
const fwExtensibleBase* CTheScripts::GetExtensibleBaseToQueryFromGUID(int guid, const char* commandName, unsigned assertFlags)
|
||
{
|
||
assertFlags &= (~GUID_ASSERT_FLAG_NOT_CLONE);
|
||
return GetExtensibleBaseToModifyFromGUID(guid, commandName, assertFlags);
|
||
}
|
||
|
||
const CItemSet* CTheScripts::GetItemSetToQueryFromGUID(int guid, const char* commandName, unsigned assertFlags)
|
||
{
|
||
assertFlags &= (~GUID_ASSERT_FLAG_NOT_CLONE);
|
||
return GetItemSetToModifyFromGUID(guid, commandName, assertFlags);
|
||
}
|
||
|
||
const CScriptedCoverPoint* CTheScripts::GetScriptedCoverPointToQueryFromGUID(int guid, const char* commandName, unsigned assertFlags)
|
||
{
|
||
return GetScriptedCoverPointToModifyFromGUID(guid, commandName, assertFlags);
|
||
}
|
||
|
||
int CTheScripts::GetGUIDFromEntity(fwEntity& entity)
|
||
{
|
||
return fwScriptGuid::CreateGuid(entity);
|
||
}
|
||
|
||
int CTheScripts::GetGUIDFromExtensibleBase(fwExtensibleBase& base)
|
||
{
|
||
return fwScriptGuid::GetGuidFromBase(base);
|
||
}
|
||
|
||
int CTheScripts::GetGUIDFromPreferredCoverPoint(CScriptedCoverPoint& preferredCoverPoint)
|
||
{
|
||
return fwScriptGuid::CreateGuid(preferredCoverPoint);
|
||
}
|
||
|
||
#if !__FINAL
|
||
EXTERN_PARSER_ENUM(ScriptTaskTypes);
|
||
|
||
const char* CTheScripts::GetScriptTaskName( s32 iCommandIndex )
|
||
{
|
||
return PARSER_ENUM(ScriptTaskTypes).NameFromValue(iCommandIndex);
|
||
}
|
||
|
||
|
||
const char* CTheScripts::GetScriptStatusName( u8 iScriptStatus )
|
||
{
|
||
switch( iScriptStatus )
|
||
{
|
||
case CPedScriptedTaskRecordData::EVENT_STAGE: return "WAITING_TO_START_TASK";
|
||
case CPedScriptedTaskRecordData::ACTIVE_TASK_STAGE: return "PERFORMING_TASK";
|
||
case CPedScriptedTaskRecordData::DORMANT_TASK_STAGE: return "DORMANT_TASK";
|
||
case CPedScriptedTaskRecordData::VACANT_STAGE: return "VACANT_STAGE";
|
||
case CPedScriptedTaskRecordData::GROUP_TASK_STAGE: return "GROUP_TASK_STAGE";
|
||
case CPedScriptedTaskRecordData::UNUSED_ATTRACTOR_SCRIPT_TASK_STAGE: return "ATTRACTOR_SCRIPT_TASK_STAGE";
|
||
case CPedScriptedTaskRecordData::SECONDARY_TASK_STAGE: return "SECONDARY_TASK_STAGE";
|
||
default: return "FINISHED_TASK";
|
||
}
|
||
}
|
||
#endif //!__FINAL
|
||
|
||
CPed* CTheScripts::FindLocalPlayerPed( int playerIndex, bool ASSERT_ONLY(bAssert) )
|
||
{
|
||
CPed* pPlayerPed = NULL;
|
||
|
||
if (NetworkInterface::IsGameInProgress())
|
||
{
|
||
CNetGamePlayer* pNetPlayer = NetworkInterface::GetPhysicalPlayerFromIndex(static_cast<PhysicalPlayerIndex>(playerIndex));
|
||
|
||
if (scriptVerifyf(pNetPlayer && pNetPlayer->IsMyPlayer(), "%s : %s - Can only be called on the local player", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName()))
|
||
{
|
||
pPlayerPed = pNetPlayer->GetPlayerPed();
|
||
}
|
||
}
|
||
else if (scriptVerifyf(playerIndex==0, "%s : %s - Can only be called on the local player", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName()))
|
||
{
|
||
pPlayerPed = CGameWorld::FindLocalPlayer();
|
||
}
|
||
|
||
#if __ASSERT
|
||
if (bAssert)
|
||
{
|
||
scriptAssertf(pPlayerPed, "%s : %s - Player ped doesn't exist", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName());
|
||
}
|
||
#endif
|
||
|
||
return pPlayerPed;
|
||
}
|
||
|
||
CPed* CTheScripts::FindNetworkPlayerPed( int playerIndex, bool ASSERT_ONLY(bAssert) )
|
||
{
|
||
CPed* pPlayerPed = NULL;
|
||
CNetGamePlayer* pNetPlayer = NULL;
|
||
|
||
if (NetworkInterface::IsGameInProgress())
|
||
{
|
||
if (SCRIPT_VERIFY_PLAYER_INDEX(scrThread::GetCurrentCmdName(), playerIndex))
|
||
{
|
||
pNetPlayer = NetworkInterface::GetPhysicalPlayerFromIndex(static_cast<PhysicalPlayerIndex>(playerIndex));
|
||
|
||
if (pNetPlayer)
|
||
{
|
||
pPlayerPed = pNetPlayer->GetPlayerPed();
|
||
}
|
||
}
|
||
}
|
||
else if (scriptVerifyf(playerIndex==0, "%s : %s - Can only be called on the local player", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName()))
|
||
{
|
||
pPlayerPed = CGameWorld::FindLocalPlayer();
|
||
}
|
||
|
||
#if __ASSERT
|
||
if (bAssert)
|
||
{
|
||
scriptAssertf(!pPlayerPed || pPlayerPed->GetPlayerInfo(), "%s : %s - Player %d (%s) has no player info", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName(), playerIndex, pNetPlayer ? pNetPlayer->GetLogName() : "-none-");
|
||
}
|
||
#endif
|
||
|
||
return pPlayerPed;
|
||
}
|
||
|
||
CNetGamePlayer *CTheScripts::FindNetworkPlayer( int playerIndex, bool ASSERT_ONLY(bAssert))
|
||
{
|
||
CNetGamePlayer* pNetPlayer = NULL;
|
||
|
||
if (scriptVerifyf(NetworkInterface::IsGameInProgress(), "%s : %s - A network game is not running", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName()))
|
||
{
|
||
if (SCRIPT_VERIFY_PLAYER_INDEX(scrThread::GetCurrentCmdName(), playerIndex))
|
||
{
|
||
pNetPlayer = NetworkInterface::GetPhysicalPlayerFromIndex(static_cast<PhysicalPlayerIndex>(playerIndex));
|
||
|
||
#if __ASSERT
|
||
if (bAssert)
|
||
{
|
||
scriptAssertf(pNetPlayer, "%s : %s - Network player doesn't exist", CTheScripts::GetCurrentScriptNameAndProgramCounter(), scrThread::GetCurrentCmdName());
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
return pNetPlayer;
|
||
}
|
||
|
||
bool CTheScripts::ExportGamerHandle(const rlGamerHandle* phGamer, int& handleData, int sizeOfData ASSERT_ONLY(, const char* szCommand))
|
||
{
|
||
#if __NO_OUTPUT
|
||
if(!scriptVerifyf(phGamer->IsValid(), "%s : %s - Invalid handle!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
#else
|
||
#if __ASSERT
|
||
char szToString[RL_MAX_GAMER_HANDLE_CHARS];
|
||
#endif // __ASSERT
|
||
if(!scriptVerifyf(phGamer->IsValid(), "%s : %s - Invalid handle! As String: %s", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand, phGamer->ToString(szToString)))
|
||
#endif
|
||
return false;
|
||
|
||
// script returns size in script words
|
||
if(!scriptVerifyf(sizeOfData == SCRIPT_GAMER_HANDLE_SIZE, "%s : %s - Invalid data size!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
return false;
|
||
|
||
sizeOfData *= sizeof(scrValue);
|
||
|
||
// buffer to write our handle into
|
||
u8* pHandleBuffer = reinterpret_cast<u8*>(&handleData);
|
||
|
||
// retrieve gamer handle
|
||
unsigned nExported = 0;
|
||
#if __NO_OUTPUT
|
||
if(!scriptVerifyf(phGamer->Export(pHandleBuffer, sizeOfData, &nExported), "%s : %s - Export failed!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
#else
|
||
if(!scriptVerifyf(phGamer->Export(pHandleBuffer, sizeOfData, &nExported), "%s : %s - Export failed! As String: %s", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand, phGamer->ToString(szToString)))
|
||
#endif
|
||
return false;
|
||
if(!scriptVerifyf(nExported < GAMER_HANDLE_SIZE, "%s : %s - Increase GAMER_HANDLE_SIZE!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CTheScripts::ImportGamerHandle(rlGamerHandle* phGamer, int& handleData, int sizeOfData ASSERT_ONLY(, const char* szCommand))
|
||
{
|
||
// script returns size in script words
|
||
if(!scriptVerifyf(sizeOfData == SCRIPT_GAMER_HANDLE_SIZE, "%s : %s - Invalid data size!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
return false;
|
||
|
||
sizeOfData *= sizeof(scrValue);
|
||
|
||
// buffer to write our handle into
|
||
u8* pHandleBuffer = reinterpret_cast<u8*>(&handleData);
|
||
|
||
// retrieve gamer handle
|
||
unsigned nImported = 0;
|
||
if(!scriptVerifyf(phGamer->Import(pHandleBuffer, sizeOfData, &nImported), "%s : %s - Import failed!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
{
|
||
#if !__NO_OUTPUT
|
||
if (sizeOfData == SCRIPT_GAMER_HANDLE_SIZE)
|
||
{
|
||
scriptErrorf("CTheScripts::ImportGamerHandle() - FAILED - left to right - Service 1st 8bits from left:");
|
||
int* handleDataOut = &handleData;
|
||
for (int i=0; i<SCRIPT_GAMER_HANDLE_SIZE; i++)
|
||
scriptErrorf(".............. handleData[%d] = '%d'", i, handleDataOut[i]);
|
||
}
|
||
#endif //!__NO_OUTPUT
|
||
|
||
return false;
|
||
}
|
||
|
||
if(!scriptVerifyf(nImported < GAMER_HANDLE_SIZE, "%s : %s - Increase GAMER_HANDLE_SIZE!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
return false;
|
||
|
||
return scriptVerifyf(phGamer->IsValid(), "%s : %s - Invalid handle!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand);
|
||
}
|
||
|
||
bool CTheScripts::ImportGamerHandle(rlGamerHandle* phGamer, u8* pData ASSERT_ONLY(, const char* szCommand))
|
||
{
|
||
// retrieve gamer handle
|
||
unsigned nImported = 0;
|
||
if(!scriptVerifyf(phGamer->Import(pData, GAMER_HANDLE_SIZE, &nImported), "%s : %s - Import failed! Invalid gamerhandle: %s", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand, pData))
|
||
return false;
|
||
if(!scriptVerifyf(nImported < GAMER_HANDLE_SIZE, "%s : %s - Increase GAMER_HANDLE_SIZE!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand))
|
||
return false;
|
||
|
||
return scriptVerifyf(phGamer->IsValid(), "%s : %s - Invalid handle!", CTheScripts::GetCurrentScriptNameAndProgramCounter(), szCommand);
|
||
}
|
||
|
||
bool CTheScripts::HasEntityBeenRegisteredWithCurrentThread(const CPhysical* pPhysical)
|
||
{
|
||
const CScriptEntityExtension* pExtension = pPhysical->GetExtension<CScriptEntityExtension>();
|
||
|
||
return (pExtension && pExtension->GetScriptInfo() && pExtension->GetScriptInfo()->GetScriptId() == CGameScriptId(*GetCurrentGtaScriptThread()));
|
||
}
|
||
|
||
int CTheScripts::GetIdForEntityRegisteredWithCurrentThread(const CPhysical* pPhysical)
|
||
{
|
||
if (AssertVerify(HasEntityBeenRegisteredWithCurrentThread(pPhysical)))
|
||
{
|
||
const CScriptEntityExtension* pExtension = pPhysical->GetExtension<CScriptEntityExtension>();
|
||
|
||
return static_cast<int>(pExtension->GetScriptInfo()->GetObjectId());
|
||
}
|
||
|
||
return NULL_IN_SCRIPTING_LANGUAGE;
|
||
}
|
||
|
||
void CScriptEulers::MatrixFromEulers(Matrix34& matrix, const Vector3& eulers, EulerAngleOrder rotationOrder)
|
||
{
|
||
switch(rotationOrder)
|
||
{
|
||
case EULER_XYZ:
|
||
matrix.FromEulersXYZ(eulers);
|
||
break;
|
||
|
||
case EULER_XZY:
|
||
matrix.FromEulersXZY(eulers);
|
||
break;
|
||
|
||
case EULER_YXZ:
|
||
matrix.FromEulersYXZ(eulers);
|
||
break;
|
||
|
||
case EULER_YZX:
|
||
matrix.FromEulersYZX(eulers);
|
||
break;
|
||
|
||
case EULER_ZXY:
|
||
matrix.FromEulersZXY(eulers);
|
||
break;
|
||
|
||
case EULER_ZYX:
|
||
matrix.FromEulersZYX(eulers);
|
||
break;
|
||
|
||
default:
|
||
scriptAssertf(false, "Invalid Euler rotation order");
|
||
matrix.Identity();
|
||
break;
|
||
}
|
||
}
|
||
|
||
Vector3 CScriptEulers::MatrixToEulers(const Matrix34& matrix, EulerAngleOrder rotationOrder)
|
||
{
|
||
Vector3 eulers;
|
||
|
||
switch(rotationOrder)
|
||
{
|
||
case EULER_XYZ:
|
||
matrix.ToEulersXYZ(eulers);
|
||
break;
|
||
|
||
case EULER_XZY:
|
||
matrix.ToEulersXZY(eulers);
|
||
break;
|
||
|
||
case EULER_YXZ:
|
||
matrix.ToEulersYXZ(eulers);
|
||
break;
|
||
|
||
case EULER_YZX:
|
||
matrix.ToEulersYZX(eulers);
|
||
break;
|
||
|
||
case EULER_ZXY:
|
||
matrix.ToEulersZXY(eulers);
|
||
break;
|
||
|
||
case EULER_ZYX:
|
||
matrix.ToEulersZYX(eulers);
|
||
break;
|
||
|
||
default:
|
||
scriptAssertf(false, "Invalid Euler rotation order");
|
||
eulers.Zero();
|
||
break;
|
||
}
|
||
|
||
return eulers;
|
||
}
|
||
|
||
void CScriptEulers::QuaternionFromEulers(Quaternion& quat, const Vector3& eulers, EulerAngleOrder rotationOrder)
|
||
{
|
||
switch(rotationOrder)
|
||
{
|
||
case EULER_XYZ:
|
||
quat.FromEulers(eulers, eEulerOrderXYZ);
|
||
break;
|
||
|
||
case EULER_XZY:
|
||
quat.FromEulers(eulers, eEulerOrderXZY);
|
||
break;
|
||
|
||
case EULER_YXZ:
|
||
quat.FromEulers(eulers, eEulerOrderYXZ);
|
||
break;
|
||
|
||
case EULER_YZX:
|
||
quat.FromEulers(eulers, eEulerOrderYZX);
|
||
break;
|
||
|
||
case EULER_ZXY:
|
||
quat.FromEulers(eulers, eEulerOrderZXY);
|
||
break;
|
||
|
||
case EULER_ZYX:
|
||
quat.FromEulers(eulers, eEulerOrderZYX);
|
||
break;
|
||
|
||
default:
|
||
scriptAssertf(false, "CScriptEulers::QuaternionFromEulers - Invalid Euler rotation order");
|
||
quat.Identity();
|
||
break;
|
||
}
|
||
}
|
||
|
||
Vector3 CScriptEulers::QuaternionToEulers(Quaternion& quat, EulerAngleOrder rotationOrder)
|
||
{
|
||
Vector3 eulers;
|
||
|
||
switch(rotationOrder)
|
||
{
|
||
case EULER_XYZ:
|
||
quat.ToEulers(eulers, eEulerOrderXYZ);
|
||
break;
|
||
|
||
case EULER_XZY:
|
||
quat.ToEulers(eulers, eEulerOrderXZY);
|
||
break;
|
||
|
||
case EULER_YXZ:
|
||
quat.ToEulers(eulers, eEulerOrderYXZ);
|
||
break;
|
||
|
||
case EULER_YZX:
|
||
quat.ToEulers(eulers, eEulerOrderYZX);
|
||
break;
|
||
|
||
case EULER_ZXY:
|
||
quat.ToEulers(eulers, eEulerOrderZXY);
|
||
break;
|
||
|
||
case EULER_ZYX:
|
||
quat.ToEulers(eulers, eEulerOrderZYX);
|
||
break;
|
||
|
||
default:
|
||
scriptAssertf(false, "CScriptEulers::QuaternionToEulers - Invalid Euler rotation order");
|
||
eulers.Zero();
|
||
break;
|
||
}
|
||
|
||
return eulers;
|
||
}
|
||
|
||
// *************************************************************************************************
|
||
|
||
// CPersistentScriptGlobals CTheScripts::PersistentScriptGlobals;
|
||
|
||
/*
|
||
void CPersistentScriptGlobals::Init()
|
||
{
|
||
m_nSizeOfPersistentGlobalsBuffer = 0;
|
||
m_pBackupOfPersistentGlobalsBuffer = NULL;
|
||
m_nOffsetToStartOfPersistentGlobalsBuffer = -1;
|
||
}
|
||
|
||
void CPersistentScriptGlobals::Clear()
|
||
{
|
||
m_nSizeOfPersistentGlobalsBuffer = 0;
|
||
if (m_pBackupOfPersistentGlobalsBuffer)
|
||
{
|
||
delete[] m_pBackupOfPersistentGlobalsBuffer;
|
||
}
|
||
m_pBackupOfPersistentGlobalsBuffer = NULL;
|
||
|
||
m_nOffsetToStartOfPersistentGlobalsBuffer = -1;
|
||
}
|
||
|
||
void CPersistentScriptGlobals::RegisterPersistentGlobalVariables(int *pStartOfPersistentGlobals, int nSizeOfBuffer)
|
||
{
|
||
u8 *pStartOfGlobalsMemory = reinterpret_cast<u8*>(scrProgram::GetGlobals());
|
||
u8 *pStartOfPersistents = reinterpret_cast<u8*>(pStartOfPersistentGlobals);
|
||
int nOffsetToGlobalsInBytes = pStartOfPersistents - pStartOfGlobalsMemory;
|
||
|
||
scriptAssertf( (nOffsetToGlobalsInBytes >= 0) && (nOffsetToGlobalsInBytes < static_cast<int>(sizeof(scrValue) * scrProgram::GetGlobalSize())), "CPersistentScriptGlobals::RegisterPersistentGlobalVariables - offset to persistent globals is out of range");
|
||
scriptAssertf( (nOffsetToGlobalsInBytes + nSizeOfBuffer) <= static_cast<int>(sizeof(scrValue) * scrProgram::GetGlobalSize()), "CPersistentScriptGlobals::RegisterPersistentGlobalVariables - persistent globals structure extends past the end of the global script memory");
|
||
|
||
scriptAssertf((scrProgram::GetGlobals() + (nOffsetToGlobalsInBytes/sizeof(scrValue)) ) == reinterpret_cast<scrValue*>(pStartOfPersistentGlobals), "CPersistentScriptGlobals::RegisterPersistentGlobalVariables - I've made a mistake in my calculations - Graeme");
|
||
|
||
scriptAssertf( (m_nSizeOfPersistentGlobalsBuffer == 0) || (m_nSizeOfPersistentGlobalsBuffer == nSizeOfBuffer), "CPersistentScriptGlobals::RegisterPersistentGlobalVariables - attempting to change the size of the persistent globals structure");
|
||
scriptAssertf( (m_nOffsetToStartOfPersistentGlobalsBuffer == -1) || (m_nOffsetToStartOfPersistentGlobalsBuffer == nOffsetToGlobalsInBytes), "CPersistentScriptGlobals::RegisterPersistentGlobalVariables - attempting to change the offset of the persistent globals structure");
|
||
|
||
scriptAssertf(!m_pBackupOfPersistentGlobalsBuffer, "CPersistentScriptGlobals::RegisterPersistentGlobalVariables - didn't expect the backup buffer to be allocated at this point");
|
||
|
||
Clear();
|
||
|
||
m_nSizeOfPersistentGlobalsBuffer = nSizeOfBuffer;
|
||
m_nOffsetToStartOfPersistentGlobalsBuffer = nOffsetToGlobalsInBytes;
|
||
}
|
||
|
||
bool CPersistentScriptGlobals::StorePersistentGlobalsInBackupBuffer()
|
||
{
|
||
if (m_nSizeOfPersistentGlobalsBuffer == 0)
|
||
{
|
||
scriptAssertf(m_nOffsetToStartOfPersistentGlobalsBuffer == -1, "CPersistentScriptGlobals::StorePersistentGlobalsInBackupBuffer - size of buffer is 0 but offset is not -1");
|
||
return true; // returning false would probably suggest that the function had failed rather than that the buffer didn't need to be allocated
|
||
}
|
||
|
||
if (m_pBackupOfPersistentGlobalsBuffer)
|
||
{
|
||
scriptAssertf(0, "CPersistentScriptGlobals::StorePersistentGlobalsInBackupBuffer - didn't expect backup buffer to already be allocated at this stage");
|
||
delete[] m_pBackupOfPersistentGlobalsBuffer;
|
||
m_pBackupOfPersistentGlobalsBuffer = NULL;
|
||
}
|
||
|
||
scriptAssertf( (m_nOffsetToStartOfPersistentGlobalsBuffer >= 0) && (m_nOffsetToStartOfPersistentGlobalsBuffer < static_cast<int>(sizeof(scrValue) * scrProgram::GetGlobalSize())), "CPersistentScriptGlobals::StorePersistentGlobalsInBackupBuffer - offset to persistent globals is out of range");
|
||
scriptAssertf( (m_nOffsetToStartOfPersistentGlobalsBuffer + m_nSizeOfPersistentGlobalsBuffer) <= static_cast<int>(sizeof(scrValue) * scrProgram::GetGlobalSize()), "CPersistentScriptGlobals::StorePersistentGlobalsInBackupBuffer - persistent globals structure extends past the end of the global script memory");
|
||
|
||
// Allocate buffer of the correct size
|
||
m_pBackupOfPersistentGlobalsBuffer = rage_new u8[m_nSizeOfPersistentGlobalsBuffer];
|
||
if (m_pBackupOfPersistentGlobalsBuffer)
|
||
{ // Copy the global data into this buffer
|
||
const u8 *pStartOfPersistentStructureInGlobalsMemory = reinterpret_cast<const u8*>(scrProgram::GetGlobals()) + m_nOffsetToStartOfPersistentGlobalsBuffer;
|
||
sysMemCpy(m_pBackupOfPersistentGlobalsBuffer, pStartOfPersistentStructureInGlobalsMemory, m_nSizeOfPersistentGlobalsBuffer);
|
||
}
|
||
else
|
||
{
|
||
scriptAssertf(0, "CPersistentScriptGlobals::StorePersistentGlobalsInBackupBuffer - failed to allocate memory for the backup buffer");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CPersistentScriptGlobals::RestorePersistentGlobalsFromBackupBuffer()
|
||
{
|
||
bool bSucceeded = true;
|
||
|
||
if (scrProgram::GetGlobalSize() > 0)
|
||
{
|
||
if (m_pBackupOfPersistentGlobalsBuffer)
|
||
{
|
||
scriptAssertf(m_nSizeOfPersistentGlobalsBuffer > 0, "CPersistentScriptGlobals::RestorePersistentGlobalsFromBackupBuffer - size of buffer to restore must be greater than 0");
|
||
|
||
scriptAssertf( (m_nOffsetToStartOfPersistentGlobalsBuffer >= 0) && (m_nOffsetToStartOfPersistentGlobalsBuffer < static_cast<int>(sizeof(scrValue) * scrProgram::GetGlobalSize())), "CPersistentScriptGlobals::RestorePersistentGlobalsFromBackupBuffer - offset to persistent globals is out of range");
|
||
scriptAssertf( (m_nOffsetToStartOfPersistentGlobalsBuffer + m_nSizeOfPersistentGlobalsBuffer) <= static_cast<int>(sizeof(scrValue) * scrProgram::GetGlobalSize()), "CPersistentScriptGlobals::RestorePersistentGlobalsFromBackupBuffer - persistent globals structure extends past the end of the global script memory");
|
||
|
||
// Copy the contents of the backup buffer back into the global data
|
||
u8 *pStartOfPersistentStructureInGlobalsMemory = reinterpret_cast<u8*>(scrProgram::GetGlobals()) + m_nOffsetToStartOfPersistentGlobalsBuffer;
|
||
sysMemCpy(pStartOfPersistentStructureInGlobalsMemory, m_pBackupOfPersistentGlobalsBuffer, m_nSizeOfPersistentGlobalsBuffer);
|
||
}
|
||
else
|
||
{
|
||
if ( (m_nSizeOfPersistentGlobalsBuffer != 0) || (m_nOffsetToStartOfPersistentGlobalsBuffer != -1) )
|
||
{
|
||
scriptAssertf(0, "CPersistentScriptGlobals::RestorePersistentGlobalsFromBackupBuffer - no backup buffer to restore from");
|
||
bSucceeded = false;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
scriptAssertf(0, "CPersistentScriptGlobals::RestorePersistentGlobalsFromBackupBuffer - no global variables have been allocated at this stage");
|
||
bSucceeded = false;
|
||
}
|
||
|
||
// free the backup buffer
|
||
if (m_pBackupOfPersistentGlobalsBuffer)
|
||
{
|
||
delete[] m_pBackupOfPersistentGlobalsBuffer;
|
||
}
|
||
m_pBackupOfPersistentGlobalsBuffer = NULL;
|
||
|
||
return bSucceeded;
|
||
}
|
||
*/
|
||
|
||
// *************************************************************************************************
|
||
|
||
|
||
class CDLCScriptDataMounter : public CDataFileMountInterface
|
||
{
|
||
virtual bool LoadDataFile(const CDataFileMgr::DataFile& file)
|
||
{
|
||
switch(file.m_fileType)
|
||
{
|
||
case CDataFileMgr::DLC_SCRIPT_METAFILE:
|
||
{
|
||
CDLCScript::AddScriptData(file.m_filename);
|
||
return true;
|
||
}
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
virtual void UnloadDataFile(const CDataFileMgr::DataFile & file)
|
||
{
|
||
CDLCScript::RemoveScriptData(file.m_filename);
|
||
}
|
||
}g_dlcScriptDataMounter;
|
||
|
||
void CDLCScript::AddScriptData(const char* fileName)
|
||
{
|
||
CDLCScript* scriptData = rage_new CDLCScript;
|
||
if(PARSER.LoadObject(fileName,NULL,*scriptData))
|
||
{
|
||
if(!CDLCScript::ms_scripts.Access(scriptData->GetScriptLiteralName().GetHash()))
|
||
{
|
||
scriptData->InitScript();
|
||
CDLCScript::ms_scripts.SafeInsert(scriptData->GetScriptLiteralName().GetHash(),scriptData);
|
||
CDLCScript::ms_scripts.FinishInsertion();
|
||
}
|
||
return;
|
||
}
|
||
delete scriptData;
|
||
}
|
||
|
||
void CDLCScript::RemoveScriptData(const char* fileName)
|
||
{
|
||
CDLCScript* scriptData = rage_new CDLCScript;
|
||
if(PARSER.LoadObject(fileName, NULL, *scriptData))
|
||
{
|
||
RemoveScript(scriptData);
|
||
}
|
||
delete scriptData;
|
||
}
|
||
|
||
|
||
void CDLCScript::Init(unsigned initMode)
|
||
{
|
||
switch(initMode)
|
||
{
|
||
case INIT_CORE:
|
||
CDataFileMount::RegisterMountInterface(CDataFileMgr::DLC_SCRIPT_METAFILE, &g_dlcScriptDataMounter);
|
||
break;
|
||
case INIT_SESSION:
|
||
for(dlcScriptIterator it=ms_scripts.Begin(); it!= ms_scripts.End();++it)
|
||
{
|
||
(*it)->InitScript();
|
||
}
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
void CDLCScript::Update()
|
||
{
|
||
for(dlcScriptIterator it=ms_scripts.Begin(); it!= ms_scripts.End();++it)
|
||
{
|
||
(*it)->UpdateScript();
|
||
}
|
||
}
|
||
|
||
void CDLCScript::Shutdown(unsigned shutdownMode)
|
||
{
|
||
switch(shutdownMode)
|
||
{
|
||
case SHUTDOWN_SESSION:
|
||
{
|
||
for(dlcScriptIterator it=ms_scripts.Begin(); it!= ms_scripts.End();++it)
|
||
{
|
||
(*it)->ShutdownScript();
|
||
}
|
||
}
|
||
break;
|
||
case SHUTDOWN_WITH_MAP_LOADED:
|
||
{
|
||
for(dlcScriptIterator it=ms_scripts.Begin(); it!= ms_scripts.End();++it)
|
||
{
|
||
RemoveScript((*it));
|
||
}
|
||
ms_scripts.Reset();
|
||
}
|
||
break;
|
||
//TODO map reset on tom's changes
|
||
}
|
||
}
|
||
|
||
void CDLCScript::InitScript()
|
||
{
|
||
const strLocalIndex scrIndex = g_StreamedScripts.FindSlotFromHashKey(m_startupScript.GetHash());
|
||
if (Verifyf(scrIndex.IsValid(), "DLC Script %s can't be found", m_startupScript.GetCStr()))
|
||
{
|
||
m_request.Request(scrIndex, g_StreamedScripts.GetStreamingModuleId(), STRFLAG_PRIORITY_LOAD|STRFLAG_MISSION_REQUIRED);
|
||
m_state = CDLCScript::DLC_SCR_REQUESTED;
|
||
}
|
||
}
|
||
|
||
void CDLCScript::UpdateScript()
|
||
{
|
||
switch (m_state)
|
||
{
|
||
case CDLCScript::DLC_SCR_REQUESTED:
|
||
{
|
||
if ( m_request.HasLoaded() )
|
||
{
|
||
const int objIdx = m_request.GetRequestId().Get();
|
||
const char* progName = "";
|
||
|
||
m_request.ClearRequiredFlags(STRFLAG_MISSION_REQUIRED);
|
||
|
||
#if !__NO_OUTPUT
|
||
if( m_startupScript.GetCStr() != NULL )
|
||
progName = m_startupScript.GetCStr();
|
||
#endif
|
||
|
||
m_thread = CTheScripts::GtaStartNewThreadWithProgramId(g_StreamedScripts.GetProgramId(objIdx), NULL, 0, m_scriptCallstackSize, progName);
|
||
m_request.Release();
|
||
|
||
if (Verifyf(m_thread!= THREAD_INVALID, "Error launching program %s", progName))
|
||
{
|
||
m_state = CDLCScript::DLC_SCR_LOADED;
|
||
}
|
||
}
|
||
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void CDLCScript::ShutdownScript()
|
||
{
|
||
m_request.Release();
|
||
if (m_thread != THREAD_INVALID)
|
||
{
|
||
scrThread::KillThread(m_thread);
|
||
m_thread = THREAD_INVALID;
|
||
strLocalIndex slot = g_StreamedScripts.FindSlotFromHashKey(GetScriptLiteralName().GetHash());
|
||
strIndex idx =g_StreamedScripts.GetStreamingIndex(slot);
|
||
strStreamingEngine::GetInfo().RemoveObject(idx);
|
||
}
|
||
m_state = CDLCScript::DLC_SCR_NONE;
|
||
}
|
||
|
||
void CDLCScript::RemoveScript(CDLCScript* dlcScript)
|
||
{
|
||
if(CDLCScript** curScriptPtr = CDLCScript::ms_scripts.SafeGet(dlcScript->GetScriptLiteralName().GetHash()))
|
||
{
|
||
CDLCScript* curScript = (*curScriptPtr);
|
||
if(curScript)
|
||
{
|
||
curScript->ShutdownScript();
|
||
curScript->GetRequest().StreamingRemove();
|
||
ms_scripts.Remove(ms_scripts.GetIndexFromDataPtr(curScriptPtr));
|
||
}
|
||
}
|
||
}
|
||
|
||
bool CDLCScript::ContainsScript(atLiteralHashValue nameHash)
|
||
{
|
||
if(CDLCScript::ms_scripts.Access(nameHash.GetHash()))
|
||
return true;
|
||
return false;
|
||
}
|
||
|
||
#if RSG_PC && ENABLE_SCRIPT_TAMPER_CHECKER
|
||
|
||
atRangeArray<bool, scrProgram::MAX_GLOBAL_BLOCKS> CScriptGlobalTamperChecker::ms_abValidPage;
|
||
bool CScriptGlobalTamperChecker::ms_bTamperingDetected = false;
|
||
s32 CScriptGlobalTamperChecker::ms_cUncheckedSection = 0;
|
||
CScriptGlobalTamperCheckerTunablesListener CScriptGlobalTamperChecker::ms_pScriptGlobalTamperTunablesListener;
|
||
|
||
void CScriptGlobalTamperChecker::Initialize()
|
||
{
|
||
// Add the listener
|
||
Tunables::GetInstance().AddListener(&ms_pScriptGlobalTamperTunablesListener);
|
||
}
|
||
void CScriptGlobalTamperChecker::Reset()
|
||
{
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
ms_abValidPage[i] = false;
|
||
}
|
||
ms_bTamperingDetected = false;
|
||
}
|
||
|
||
bool CScriptGlobalTamperChecker::CurrentGlobalsDifferFromPreviousFrame(int &page)
|
||
{
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
if (ms_abValidPage[i] && (ms_cUncheckedSection == 0))
|
||
{
|
||
if (HaveGlobalsBeenWrittenToSinceReset(i))
|
||
{
|
||
page = i;
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return ms_bTamperingDetected;
|
||
}
|
||
|
||
void CScriptGlobalTamperChecker::Update()
|
||
{
|
||
Assertf(ms_cUncheckedSection == 0, "Resetting Global Write Tracking in unchecked Section! Called Begin without End?");
|
||
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
if (scrProgram::GetGlobals(i) && ResetGlobalWriteTracking(i))
|
||
{
|
||
ms_abValidPage[i]= true;
|
||
}
|
||
else
|
||
{
|
||
ms_abValidPage[i] = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
//sets the memory for the globals as write only, letting us catch any
|
||
//exceptional cases left over in code
|
||
void CScriptGlobalTamperChecker::LockGlobalsMemory()
|
||
{
|
||
#if !RSG_FINAL
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
if (scrProgram::GetGlobals(i))
|
||
{
|
||
LockGlobalsMemory(i);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
//unlock the globals memory for the script update
|
||
void CScriptGlobalTamperChecker::UnlockGlobalsMemory()
|
||
{
|
||
#if !RSG_FINAL
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
if (scrProgram::GetGlobals(i))
|
||
{
|
||
UnlockGlobalsMemory(i);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
// Changes between a call to this and a call to EndUncheckedSection
|
||
// will not register as tampering
|
||
void CScriptGlobalTamperChecker::BeginUncheckedSection()
|
||
{
|
||
// Do tamper check now as any results will be invalidated
|
||
// once we end the unchecked section
|
||
int page = -1;
|
||
ms_bTamperingDetected = NetworkInterface::IsGameInProgress() && (ms_cUncheckedSection == 0) && CurrentGlobalsDifferFromPreviousFrame(page);
|
||
if(ms_cUncheckedSection == 0 && PARAM_scriptProtectGlobals.Get())
|
||
{
|
||
CScriptGlobalTamperChecker::UnlockGlobalsMemory();
|
||
}
|
||
ms_cUncheckedSection++;
|
||
}
|
||
|
||
void CScriptGlobalTamperChecker::EndUncheckedSection()
|
||
{
|
||
ms_cUncheckedSection--;
|
||
if(ms_cUncheckedSection == 0)
|
||
{
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
if(ms_abValidPage[i])
|
||
{
|
||
ResetGlobalWriteTracking(i);
|
||
}
|
||
}
|
||
|
||
if(PARAM_scriptProtectGlobals.Get())
|
||
{
|
||
CScriptGlobalTamperChecker::LockGlobalsMemory();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CScriptGlobalTamperChecker::FakeTamper(const s32 offsetIndex)
|
||
{
|
||
#if !RSG_FINAL
|
||
for (s32 i=0; i<scrProgram::MAX_GLOBAL_BLOCKS; i++)
|
||
{
|
||
if (scrProgram::GetGlobals(i) && ResetGlobalWriteTracking(i))
|
||
{
|
||
FakeTamper(i,offsetIndex);
|
||
}
|
||
}
|
||
#else
|
||
(void)offsetIndex;
|
||
#endif
|
||
}
|
||
|
||
bool CScriptGlobalTamperChecker::ResetGlobalWriteTracking(s32 pageIndex)
|
||
{
|
||
scrValue* globals = scrProgram::GetGlobals(pageIndex);
|
||
if (globals)
|
||
{
|
||
const s32 globalSize = scrProgram::GetGlobalSize(pageIndex);
|
||
return (ResetWriteWatch(globals, globalSize*sizeof(scrValue)) == 0);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void CScriptGlobalTamperCheckerTunablesListener::OnTunablesRead()
|
||
{
|
||
m_IsDisabled = Tunables::GetInstance().TryAccess(MP_GLOBAL_HASH, ATSTRINGHASH("DISABLE_SCRIPT_STATISTICS", 0xD4329E00), false);
|
||
}
|
||
|
||
bool CScriptGlobalTamperChecker::ShouldCheckGlobalBlock(s32 pageIndex)
|
||
{
|
||
// Should we ignore everything because of tuneables?
|
||
if(ms_pScriptGlobalTamperTunablesListener.IsDisabled())
|
||
return false;
|
||
|
||
//TODO: Extend to flexibly include other buckets via a tunable arrayn
|
||
u32 blockNameHash = scrProgram::GetGlobalNameHash(pageIndex);
|
||
|
||
const int numIgnorableGlobalBlocks = 3;
|
||
const u32 ignoreableGlobalBlockNameHashes[numIgnorableGlobalBlocks] = {
|
||
ATSTRINGHASH("startup", 0x41D6F794),
|
||
ATSTRINGHASH("ugc_global_registration", 0x19F4EE3D),
|
||
ATSTRINGHASH("global_fmmc_registration", 0x562E9707)};
|
||
|
||
for(int i = 0; i < numIgnorableGlobalBlocks; i++)
|
||
{
|
||
if(blockNameHash == ignoreableGlobalBlockNameHashes[i])
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool CScriptGlobalTamperChecker::HaveGlobalsBeenWrittenToSinceReset(s32 pageIndex)
|
||
{
|
||
if(!ShouldCheckGlobalBlock(pageIndex))
|
||
return false;
|
||
|
||
scrValue* globals = scrProgram::GetGlobals(pageIndex);
|
||
if (globals)
|
||
{
|
||
const s32 globalSize = scrProgram::GetGlobalSize(pageIndex);
|
||
|
||
void* addressArray[128];
|
||
ULONG_PTR count = 128;
|
||
ULONG pageSize;
|
||
|
||
if ( GetWriteWatch(0, globals, globalSize*sizeof(scrValue), addressArray, &count, &pageSize) == 0 )
|
||
{
|
||
if (count)
|
||
{
|
||
#if !RSG_FINAL
|
||
scriptWarningf("CScriptGlobalTamperChecker - Global %p / Page %d / Size %d / Valid Page? %x", globals, pageIndex, globalSize, ms_abValidPage[pageIndex]);
|
||
for(int i = 0; i < count && i < 128; i++)
|
||
{
|
||
scriptWarningf("\tAddress %d/%d - %p", i , count-1, addressArray[i]);
|
||
}
|
||
|
||
if(PARAM_scriptProtectGlobals.Get())
|
||
{
|
||
__debugbreak();
|
||
}
|
||
#endif
|
||
return true;
|
||
}
|
||
}
|
||
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void CScriptGlobalTamperChecker::LockGlobalsMemory(s32 pageIndex)
|
||
{
|
||
scrValue* globals = scrProgram::GetGlobals(pageIndex);
|
||
if (globals)
|
||
{
|
||
const s32 globalSize = scrProgram::GetGlobalSize(pageIndex);
|
||
sysMemLockMemory(globals, globalSize*sizeof(scrValue));
|
||
}
|
||
}
|
||
|
||
void CScriptGlobalTamperChecker::UnlockGlobalsMemory(s32 pageIndex)
|
||
{
|
||
scrValue* globals = scrProgram::GetGlobals(pageIndex);
|
||
if (globals)
|
||
{
|
||
const s32 globalSize = scrProgram::GetGlobalSize(pageIndex);
|
||
sysMemUnlockMemory(globals, globalSize*sizeof(scrValue));
|
||
}
|
||
}
|
||
|
||
void CScriptGlobalTamperChecker::FakeTamper(s32 pageIndex,const s32 offsetIndex)
|
||
{
|
||
scrValue* globals = scrProgram::GetGlobals(pageIndex);
|
||
if (globals)
|
||
{
|
||
const s32 globalSize = scrProgram::GetGlobalSize(pageIndex);
|
||
if(offsetIndex < globalSize)
|
||
{
|
||
globals[offsetIndex].Int = 123;
|
||
}
|
||
}
|
||
}
|
||
|
||
CScriptGlobalTamperChecker::UncheckedScope::UncheckedScope()
|
||
{
|
||
CScriptGlobalTamperChecker::BeginUncheckedSection();
|
||
}
|
||
|
||
CScriptGlobalTamperChecker::UncheckedScope::~UncheckedScope()
|
||
{
|
||
CScriptGlobalTamperChecker::EndUncheckedSection();
|
||
}
|
||
|
||
|
||
#endif //RSG_PC
|