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

2002 lines
59 KiB
C++
Raw Blame History

#include "SaveLoad/savegame_photo_metadata.h"
// Rage headers
#include "rline/rl.h"
#include "vector/vector3.h"
// Framework headers
#include "fwsys/gameskeleton.h"
// Game headers
#include "ai/EntityScanner.h"
#include "audio/radioaudioentity.h"
#include "frontend/MobilePhone.h"
#include "game/user.h"
#include "Network/NetworkInterface.h"
#include "Network/Live/NetworkClan.h"
#include "Network/Sessions/NetworkGameConfig.h"
#include "Network/Sessions/NetworkSession.h"
#include "Peds/PedIntelligence.h"
#include "renderer/occlusion.h"
#include "SaveLoad/savegame_channel.h"
#include "scene/world/GameWorld.h"
#include "script/script.h"
#include "text/messages.h"
#include "text/TextConversion.h"
// Constants
static const s32 MAX_NUM_VISIBLE_VEHICLES = 16;
static const s32 MAX_NUM_VISIBLE_WEAPONS = 16;
static const s32 MAX_NUM_VISIBLE_PLAYERS = 16;
static const s32 MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS = 16;
PARAM(photoUseLimeLight, "[savegame_photo] Use limelight instead of akamai");
const char *CSavegamePhotoMetadata::GetSongTitle() const
{
if (m_SongId != InvalidSongId)
{
char songTitleTextKey[16];
formatf(songTitleTextKey, "%uS", m_SongId);
if (TheText.DoesTextLabelExist(songTitleTextKey))
{
return TheText.Get(songTitleTextKey);
}
}
return "";
}
const char *CSavegamePhotoMetadata::GetSongArtist() const
{
if (m_SongId != InvalidSongId)
{
char artistTextKey[16];
formatf(artistTextKey, "%uA", m_SongId);
if (TheText.DoesTextLabelExist(artistTextKey))
{
return TheText.Get(artistTextKey);
}
}
return "";
}
void CSavegamePhotoMetadata::FillContents()
{
Vector3 vPlayerCoords = CGameWorld::FindLocalPlayerCoors();
m_fPlayerX = vPlayerCoords.x;
m_fPlayerY = vPlayerCoords.y;
m_fPlayerZ = vPlayerCoords.z;
// CTextConversion::charToAscii(CUserDisplay::AreaName.GetName(), m_AreaName, NELEM(m_AreaName));
// CTextConversion::charToAscii(CUserDisplay::StreetName.GetName(), m_StreetName, NELEM(m_StreetName));
m_AreaNameTextKey = CUserDisplay::AreaName.GetNameTextKey();
m_AreaNameTextKey.Uppercase();
m_HashOfStreetNameTextKey = CUserDisplay::StreetName.GetHashOfNameTextKey();
// if (CMessages::IsMissionTitleActive() && CLoadingText::IsActive())
if(CPauseMenu::GetCurrenMissionActive())
{
// safecpy(m_SinglePlayerMissionName, CLoadingText::GetText(), NELEM(m_SinglePlayerMissionName));
if (!CPauseMenu::GetCurrentMissionLabelIsALiteralString())
{
m_SinglePlayerMissionName = CPauseMenu::GetCurrentMissionLabel(); // This is the text key (not the translated text itself)
}
else
{ // The mission labels of Multiplayer UGC missions will be literal strings
m_SinglePlayerMissionName.Clear();
}
}
else
{
// safecpy(m_SinglePlayerMissionName, "", NELEM(m_SinglePlayerMissionName));
m_SinglePlayerMissionName.Clear();
}
m_RadioStationName = "";
if (g_RadioAudioEntity.IsPlayerRadioActive() && g_RadioAudioEntity.GetPlayerRadioStation())
{
m_RadioStationName = g_RadioAudioEntity.GetPlayerRadioStation()->GetName();
}
m_SongId = g_RadioAudioEntity.GetAudibleTrackTextId();
m_PrimaryClanIdOfPlayer = 0;
if (CNetwork::IsGameInProgress())
{
m_MpSessionID = CNetwork::GetNetworkSession().GetSnSession().GetSessionId();
NetworkClan& tClan = CLiveManager::GetNetworkClan();
if(tClan.HasPrimaryClan())
{
m_PrimaryClanIdOfPlayer = tClan.GetPrimaryClan()->m_Id;
}
}
else
{
m_MpSessionID = 0; // Can I use 0 for an invalid session ID?
}
m_UgcID = CTheScripts::GetContentIdOfCurrentUGCMission();
if (CNetwork::IsGameInProgress())
{
m_GameMode = 1;
}
else
{
m_GameMode = 0;
}
// Game Time
m_GameTimeHour = CClock::GetHour();
m_GameTimeMinute = CClock::GetMinute();
m_GameTimeSecond = CClock::GetSecond();
m_GameTimeDayOfMonth = CClock::GetDay();
m_GameTimeMonth = CClock::GetMonth() + 1; // Add 1 so that our range is [1,12]. Requested by Rob Trickey by email on 01/05/2013
m_GameTimeYear = CClock::GetYear();
// Meme content is flagged later, rather than when we fill content.
m_containsMemeText = false;
m_bMugshot = false;
m_Akamai = CSavegamePhotoMetadata::IsAkamaiEnabled();
m_UniqueId.Reset(); // I'll call GenerateNewUniqueId() later once I'm sure that the player is signed in
m_ImageSignature = 0; // This will be set by a later call to SetImageSignature()
u64 posixTime = rlGetPosixTime();
photoAssertf( (posixTime >> 32) == 0, "CSavegamePhotoMetadata::FillContents - expected the top 32 bits of the current POSIX time to be 0");
m_PosixCreationTime = (u32) (posixTime & 0xffffffff);
#if PHOTO_METADATA_STORES_WIDESCREEN_FLAG
if (CHudTools::GetWideScreen())
{
m_bIsWidescreen = true;
}
else
{
m_bIsWidescreen = false;
}
#endif // PHOTO_METADATA_STORES_WIDESCREEN_FLAG
#if PHOTO_METADATA_STORES_SELFIE_FLAG
if (CPhoneMgr::CamGetSelfieModeState())
{
m_bIsSelfie = true;
}
else
{
m_bIsSelfie = false;
}
#endif // PHOTO_METADATA_STORES_SELFIE_FLAG
if (CTheScripts::GetIsInDirectorMode())
{
m_bIsInDirectorMode = true;
}
else
{
m_bIsInDirectorMode = false;
}
m_bTakenInRockstarEditor = false;
m_ArenaTheme = 0; // These will be set later by the camera script
m_ArenaVariation = 0; // if the player is inside an arena in Multiplayer
m_bOnIslandX = false; // This flag will be set later by the camera script
// if the player is on the Island that has been added for the Island Heist DLC
#if PHOTO_METADATA_STORES_NEARBY_VEHICLES
CompileTimeAssert(CVehicleScanner::MAX_NUM_ENTITIES == MAX_NUM_VISIBLE_VEHICLES);
m_AtArrayOfVisibleVehicles.Reset();
#endif // PHOTO_METADATA_STORES_NEARBY_VEHICLES
#if PHOTO_METADATA_STORES_NEARBY_WEAPONS
CompileTimeAssert(CPedScanner::MAX_NUM_ENTITIES == MAX_NUM_VISIBLE_WEAPONS);
m_AtArrayOfVisibleWeapons.Reset();
s32 number_of_visible_weapons = 0;
#endif // PHOTO_METADATA_STORES_NEARBY_WEAPONS
#if PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
CompileTimeAssert(CPedScanner::MAX_NUM_ENTITIES == MAX_NUM_VISIBLE_PLAYERS);
m_AtArrayOfGamerTags.Reset();
s32 number_of_visible_players = 0;
#endif // PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
#if PHOTO_METADATA_STORES_NEARBY_SP_CHARS
CompileTimeAssert(CPedScanner::MAX_NUM_ENTITIES == MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS);
m_AtArrayOfSinglePlayerCharacters.Reset();
s32 number_of_single_player_characters = 0;
#endif // PHOTO_METADATA_STORES_NEARBY_SP_CHARS
CPlayerInfo* pPlayerInfo = CGameWorld::GetMainPlayerInfo();
CPed *pPlayerPed = pPlayerInfo ? pPlayerInfo->GetPlayerPed() : NULL;
if (pPlayerPed)
{
#if PHOTO_METADATA_STORES_NEARBY_VEHICLES
AddNearbyVehiclesToArrayOfVisibleVehicles(pPlayerPed);
#endif // PHOTO_METADATA_STORES_NEARBY_VEHICLES
if (CPhoneMgr::CamGetSelfieModeState())
{
photoAssertf(IsEntityVisible(pPlayerPed, false), "CSavegamePhotoMetadata::FillContents - Phone camera is in selfie mode, but player isn't visible");
#if PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
AddPedToGamerTagArray(pPlayerPed, number_of_visible_players);
#endif // PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
#if PHOTO_METADATA_STORES_NEARBY_SP_CHARS
AddPedToSinglePlayerCharacterArray(pPlayerPed, number_of_single_player_characters);
#endif // PHOTO_METADATA_STORES_NEARBY_SP_CHARS
}
CEntityScannerIterator pedIterator = pPlayerPed->GetPedIntelligence()->GetNearbyPeds();
CEntity* pEntity = pedIterator.GetFirst();
while(pEntity)
{
if (IsEntityVisible(pEntity, false))
{
if (pEntity->GetIsTypePed())
{
CPed *pPed = (CPed*) pEntity;
#if PHOTO_METADATA_STORES_NEARBY_WEAPONS
AddPedWeaponToArray(pPed, number_of_visible_weapons);
#endif // PHOTO_METADATA_STORES_NEARBY_WEAPONS
#if PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
AddPedToGamerTagArray(pPed, number_of_visible_players);
#endif // PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
#if PHOTO_METADATA_STORES_NEARBY_SP_CHARS
AddPedToSinglePlayerCharacterArray(pPed, number_of_single_player_characters);
#endif // PHOTO_METADATA_STORES_NEARBY_SP_CHARS
}
}
pEntity = pedIterator.GetNext();
}
} // if (pPlayerPed)
}
void CSavegamePhotoMetadata::SetArenaThemeAndVariation(u32 arenaTheme, u32 arenaVariation)
{
m_ArenaTheme = arenaTheme;
m_ArenaVariation = arenaVariation;
}
void CSavegamePhotoMetadata::SetOnIslandX(bool bOnIslandX)
{
m_bOnIslandX = bOnIslandX;
}
void CSavegamePhotoMetadata::GenerateNewUniqueId()
{
m_UniqueId.GenerateNewUniqueId();
}
void CSavegamePhotoMetadata::SetImageSignature(u64 signature)
{
m_ImageSignature = signature;
}
bool CSavegamePhotoMetadata::GetAkamai() const
{
return m_Akamai;
}
void CSavegamePhotoMetadata::SetAkamai(const bool akamai)
{
m_Akamai = akamai;
}
bool CSavegamePhotoMetadata::IsAkamaiEnabled()
{
return NOTFINAL_ONLY(!PARAM_photoUseLimeLight.Get() &&)
Tunables::GetInstance().TryAccess(CD_GLOBAL_HASH, ATSTRINGHASH("PHOTO_AKAMAI", 0x1973A89E), true);
}
bool CSavegamePhotoMetadata::ShouldCorrectAkamaiOnLocalLoad()
{
return Tunables::GetInstance().TryAccess(CD_GLOBAL_HASH, ATSTRINGHASH("PHOTO_AKAMAI_FIX_META_ON_LOAD", 0x850243CE), true);
}
bool CSavegamePhotoMetadata::ShouldCorrectAkamaiOnUpload()
{
return Tunables::GetInstance().TryAccess(CD_GLOBAL_HASH, ATSTRINGHASH("PHOTO_AKAMAI_FIX_META_ON_UPLOAD", 0x7EFC139A), true);
}
#define LOCATION_KEY "loc"
#define AREA_KEY "area"
#define STREET_KEY "street"
#define SINGLE_PLAYER_MISSION_NAME_KEY "nm"
#define RADIO_STATION_KEY "rds"
#define SONG_KEY "scr"
/*
if (bSuccess)
{
if (CNetwork::IsGameInProgress())
{
switch (CNetwork::GetNetworkSession().GetMatchConfig().GetGameMode())
}
else
{
bSuccess = rsonWriter.WriteString("mode", "SP");
}
}
*/
// "mode" - string indicating the game mode, e.g. (SP, FREEMODE, DEATHMATCH, C&C etc)
// In code, we only know about the containing mode at the moment (freemode).
// I<>m working on transition sessions with Bobby at the moment, from that you can grab an activity type which will let you know the sub-mode (DM, race, base-jump, etc)
#define GAME_MODE_KEY "mode"
// "mid": "unique mission id e.g. 501276516e8d7d22fd67c32d" Mission UGC ID (free missions only)
// Script would need to give us this. They<65>ll know <20> just give them a script command to fill this in.
#define UGC_MISSION_UNIQUE_ID_KEY "mid"
// "sid" - string containing session id (MP only)
// CNetwork::GetNetworkSession().GetSnSession().GetSessionId()
#define MP_SESSION_ID_KEY "sid"
#define MP_CLAN_ID_KEY "crewid"
#define GAME_TIME_KEY "time"
#define GAME_TIME_HOUR "hour"
#define GAME_TIME_MINUTE "minute"
#define GAME_TIME_SECOND "second"
#define GAME_TIME_DAY "day"
#define GAME_TIME_MONTH "month"
#define GAME_TIME_YEAR "year"
#define VEHICLE_MODELS_KEY "veh" // Array of hashes of model names of visible vehicles
#define WEAPON_HASH_ARRAY_KEY "weap" // Array of hashes of weapons equipped by visible peds
#define GAMERTAG_ARRAY_KEY "plyrs" // Array of strings containing the User IDs of visible players - Bug 1927221
#define SINGLE_PLAYER_CHARACTERS_KEY "char" // Array of strings containing text labels of single player character names
#define WIDESCREEN_KEY "ws" // A flag to say whether the photo was taken on a console with the display set to widescreen
#define SELFIE_KEY "slf" // A flag to say whether the photo is a selfie
#define DIRECTOR_KEY "drctr" // A flag to say whether the photo was taken during director mode
#define ROCKSTAR_EDITOR_KEY "rsedtr" // A flag to say whether the photo was taken in the Rockstar Editor
#define AKAMAI_KEY "cv"
// game time
// real world time
// "meme" - Flag indicating if this was generated via the meme editor
#define MEME_TEXT_KEY "meme"
// "mug" - Flag to say whether the photo is a mugshot taken by James Adwick's MP character creation script
#define MUGSHOT_KEY "mug"
// "uid" - a unique Id which we use to check if a local photo also exists on the cloud
#define UNIQUE_PHOTO_ID_KEY "uid"
// "sign" - a hash value calculated from the image data. When loading, this can be used to verify that the photo is not a dodgy image that was created outside the game.
#define IMAGE_SIGNATURE_KEY "sign"
// "creat" - POSIX creation time
#define POSIX_CREATION_TIME_KEY "creat"
// Store the arena theme and variation if the player took the photo while inside an arena in Multiplayer
// A theme index of 0 means that the player was not in an arena
#define ARENA_THEME_INDEX_KEY "arena_t"
#define ARENA_VARIATION_INDEX_KEY "arena_v"
#define ON_ISLAND_X_KEY "onislandx"
#if __BANK
bool CSavegamePhotoMetadata::sm_bDisplayBoundingRectanglesForPeds = false;
bool CSavegamePhotoMetadata::sm_bSaveLocation = true;
bool CSavegamePhotoMetadata::sm_bSaveArea = true;
bool CSavegamePhotoMetadata::sm_bSaveStreet = true;
bool CSavegamePhotoMetadata::sm_bSaveMissionName = true;
bool CSavegamePhotoMetadata::sm_bSaveSong = true;
bool CSavegamePhotoMetadata::sm_bSaveRadioStation = true;
bool CSavegamePhotoMetadata::sm_bSaveMpSessionID = true;
bool CSavegamePhotoMetadata::sm_bSaveClanID = true;
bool CSavegamePhotoMetadata::sm_bSaveUgcID = true;
bool CSavegamePhotoMetadata::sm_bSaveTheGameMode = true;
bool CSavegamePhotoMetadata::sm_bSaveTheGameTime = true;
bool CSavegamePhotoMetadata::sm_bSaveTheMemeFlag = true;
bool CSavegamePhotoMetadata::sm_bSaveTheUniqueId = true;
bool CSavegamePhotoMetadata::sm_bSaveThePosixCreationTime = true;
bool CSavegamePhotoMetadata::sm_bSaveArenaThemeAndVariation = true;
bool CSavegamePhotoMetadata::sm_bSaveOnIslandX = true;
#endif // __BANK
bool CSavegamePhotoMetadata::WriteMetadataToString(char *pStringToFill, u32 maxLengthOfString, bool BANK_ONLY(bDebugLessData)) const
{
memset(pStringToFill, 0, maxLengthOfString);
RsonWriter rsonWriter(pStringToFill, maxLengthOfString, RSON_FORMAT_JSON);
rsonWriter.Reset();
bool bSuccess = rsonWriter.Begin(NULL, NULL); // Top-level structure to contain all the rest of the data
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveLocation) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.Begin(LOCATION_KEY, NULL);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteFloat("x", m_fPlayerX);
if (bSuccess)
{
bSuccess = rsonWriter.WriteFloat("y", m_fPlayerY);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteFloat("z", m_fPlayerZ);
}
}
if (bSuccess)
{
bSuccess = rsonWriter.End();
}
}
// "area" - string with the area name of the image location
// Change the following three to text labels instead of using the translated text
// CPopZone::m_associatedTextId is stored as a u64. Other code is casting to a char* though so hopefully I can treat it as a string
// It looks like CPathNode::m_streetNameHash is stored as a hash though so the json file will either need to include this u32 or the translated name
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveArea) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteString(AREA_KEY, m_AreaNameTextKey);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveStreet) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteUns(STREET_KEY, m_HashOfStreetNameTextKey);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveMissionName) )
#endif // __BANK
{
// "nm" - string containing the name of the SP mission (SP missions only)
if (bSuccess)
{
bSuccess = rsonWriter.WriteString(SINGLE_PLAYER_MISSION_NAME_KEY, m_SinglePlayerMissionName);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveRadioStation) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteString(RADIO_STATION_KEY, m_RadioStationName);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveSong) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteUns(SONG_KEY, m_SongId);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveMpSessionID) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteHex64(MP_SESSION_ID_KEY, m_MpSessionID); // Or should this be WriteUns64?
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveClanID) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt64(MP_CLAN_ID_KEY, m_PrimaryClanIdOfPlayer);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveUgcID) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteString(UGC_MISSION_UNIQUE_ID_KEY, m_UgcID);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveTheGameMode) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteString(GAME_MODE_KEY, GetStringFromGameMode(m_GameMode));
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveTheMemeFlag) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool( MEME_TEXT_KEY, m_containsMemeText );
}
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool( MUGSHOT_KEY, m_bMugshot );
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveTheUniqueId) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt( UNIQUE_PHOTO_ID_KEY, m_UniqueId.GetValue() );
}
}
// Game Time
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveTheGameTime) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.Begin(GAME_TIME_KEY, NULL);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(GAME_TIME_HOUR, m_GameTimeHour);
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(GAME_TIME_MINUTE, m_GameTimeMinute);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(GAME_TIME_SECOND, m_GameTimeSecond);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(GAME_TIME_DAY, m_GameTimeDayOfMonth);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(GAME_TIME_MONTH, m_GameTimeMonth);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(GAME_TIME_YEAR, m_GameTimeYear);
}
}
if (bSuccess)
{
bSuccess = rsonWriter.End();
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveThePosixCreationTime) )
#endif // __BANK
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteInt(POSIX_CREATION_TIME_KEY, (s32) m_PosixCreationTime);
}
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveArenaThemeAndVariation) )
#endif // __BANK
{
if (m_ArenaTheme != 0) // Only save the arena theme and variation if the theme is non-zero (i.e. the photo was taken in an arena)
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteUns(ARENA_THEME_INDEX_KEY, m_ArenaTheme);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteUns(ARENA_VARIATION_INDEX_KEY, m_ArenaVariation);
}
}
}
#if PHOTO_METADATA_STORES_WIDESCREEN_FLAG
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool(WIDESCREEN_KEY, m_bIsWidescreen);
}
#endif // PHOTO_METADATA_STORES_WIDESCREEN_FLAG
#if PHOTO_METADATA_STORES_SELFIE_FLAG
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool(SELFIE_KEY, m_bIsSelfie);
}
#endif // PHOTO_METADATA_STORES_SELFIE_FLAG
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool(DIRECTOR_KEY, m_bIsInDirectorMode);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool(ROCKSTAR_EDITOR_KEY, m_bTakenInRockstarEditor);
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool(AKAMAI_KEY, m_Akamai);
}
#if __BANK
if ( (bDebugLessData == false) || (sm_bSaveOnIslandX) )
#endif // __BANK
{
if (m_bOnIslandX) // Only save the flag if it's true (i.e. the photo was taken on the Heist Island)
{
if (bSuccess)
{
bSuccess = rsonWriter.WriteBool(ON_ISLAND_X_KEY, m_bOnIslandX);
}
}
}
if (bSuccess)
{
bSuccess = rsonWriter.WriteUns64(IMAGE_SIGNATURE_KEY, m_ImageSignature);
}
#if PHOTO_METADATA_STORES_NEARBY_VEHICLES
WriteVehiclesToJson(rsonWriter, bSuccess);
#endif // PHOTO_METADATA_STORES_NEARBY_VEHICLES
#if PHOTO_METADATA_STORES_NEARBY_WEAPONS
WriteWeaponsToJson(rsonWriter, bSuccess);
#endif // PHOTO_METADATA_STORES_NEARBY_WEAPONS
#if PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
WriteGamerTagsToJson(rsonWriter, bSuccess);
#endif // PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
#if PHOTO_METADATA_STORES_NEARBY_SP_CHARS
WriteSinglePlayerCharacterTextLabelsToJson(rsonWriter, bSuccess);
#endif // PHOTO_METADATA_STORES_NEARBY_SP_CHARS
if (bSuccess)
{
bSuccess = rsonWriter.End(); // Close the top-level structure
}
return bSuccess;
}
void CSavegamePhotoMetadata::GetPhotoLocation(Vector3& vLocation) const
{
vLocation.x = m_fPlayerX;
vLocation.y = m_fPlayerY;
vLocation.z = m_fPlayerZ;
}
void CSavegamePhotoMetadata::ReadStringFromMetadata(RsonReader &rsonReader, RsonReader &valueReader, const char *pMemberName, atString &stringToFill)
{
char stringFromMetadata[256];
safecpy(stringFromMetadata, "", NELEM(stringFromMetadata));
if (rsonReader.GetMember(pMemberName, &valueReader))
{
valueReader.AsString(stringFromMetadata, NELEM(stringFromMetadata));
}
if (strlen(stringFromMetadata) > 0)
{
stringToFill = stringFromMetadata;
}
else
{
stringToFill.Clear();
}
}
bool CSavegamePhotoMetadata::ReadMetadataFromString(const char *pString)
{
if (pString == NULL)
{
photoAssertf(0, "CSavegamePhotoMetadata::ReadMetadataFromString - pString is NULL");
return false;
}
u32 lengthOfString = ustrlen(pString);
// validation does not appreciate a null terminator
if ( (lengthOfString > 0) && (pString[lengthOfString - 1] == '\0') )
{
photoDisplayf("CSavegamePhotoMetadata::ReadMetadataFromString - reduce string length by 1 so that the null terminator is ignored");
lengthOfString -= 1;
}
// sometimes, the closing ']' CDATA blocks are included in the data size
while ( (lengthOfString > 0) && (pString[lengthOfString - 1] == ']') )
{
photoDisplayf("CSavegamePhotoMetadata::ReadMetadataFromString - reduce string length by 1 so that a ']' is ignored");
lengthOfString -= 1;
}
if (!RsonReader::ValidateJson(pString, lengthOfString))
{
photoDisplayf("CSavegamePhotoMetadata::ReadMetadataFromString - json data is not valid. The string is %s", pString);
photoAssertf(0, "CSavegamePhotoMetadata::ReadMetadataFromString - json data is not valid. The string is %s", pString);
return false;
}
RsonReader rsonReader(pString, lengthOfString);
m_fPlayerX = 0.0f;
m_fPlayerY = 0.0f;
m_fPlayerZ = 0.0f;
RsonReader valueReader;
if (rsonReader.GetMember(LOCATION_KEY, &valueReader))
{
RsonReader coordReader;
float fCoord;
if (valueReader.GetMember("x", &coordReader))
{
if (coordReader.AsFloat(fCoord))
{
m_fPlayerX = fCoord;
}
}
if (valueReader.GetMember("y", &coordReader))
{
if (coordReader.AsFloat(fCoord))
{
m_fPlayerY = fCoord;
}
}
if (valueReader.GetMember("z", &coordReader))
{
if (coordReader.AsFloat(fCoord))
{
m_fPlayerZ = fCoord;
}
}
}
ReadStringFromMetadata(rsonReader, valueReader, AREA_KEY, m_AreaNameTextKey);
m_HashOfStreetNameTextKey = 0;
if (rsonReader.GetMember(STREET_KEY, &valueReader))
{
valueReader.AsUns(m_HashOfStreetNameTextKey);
}
ReadStringFromMetadata(rsonReader, valueReader, SINGLE_PLAYER_MISSION_NAME_KEY, m_SinglePlayerMissionName);
ReadStringFromMetadata(rsonReader, valueReader, RADIO_STATION_KEY, m_RadioStationName);
m_SongId = InvalidSongId;
if (rsonReader.GetMember(SONG_KEY, &valueReader))
{
valueReader.AsUns(m_SongId);
}
m_MpSessionID = 0;
if (rsonReader.GetMember(MP_SESSION_ID_KEY, &valueReader))
{
valueReader.AsUns64(m_MpSessionID);
}
m_PrimaryClanIdOfPlayer = 0;
if (rsonReader.GetMember(MP_CLAN_ID_KEY, &valueReader))
{
valueReader.AsInt64(m_PrimaryClanIdOfPlayer);
}
ReadStringFromMetadata(rsonReader, valueReader, UGC_MISSION_UNIQUE_ID_KEY, m_UgcID);
atString gameModeString;
ReadStringFromMetadata(rsonReader, valueReader, GAME_MODE_KEY, gameModeString);
m_GameMode = GetGameModeFromString(gameModeString.c_str());
m_containsMemeText = false;
if (rsonReader.GetMember(MEME_TEXT_KEY, &valueReader))
{
valueReader.AsBool(m_containsMemeText);
}
m_bMugshot = false;
if (rsonReader.GetMember(MUGSHOT_KEY, &valueReader))
{
valueReader.AsBool(m_bMugshot);
}
m_UniqueId.Reset();
if (rsonReader.GetMember(UNIQUE_PHOTO_ID_KEY, &valueReader))
{
int nUniqueId = 0;
valueReader.AsInt(nUniqueId);
m_UniqueId.Set(nUniqueId, false);
}
m_GameTimeHour = 0;
m_GameTimeMinute = 0;
m_GameTimeSecond = 0;
m_GameTimeDayOfMonth = 1;
m_GameTimeMonth = 1;
m_GameTimeYear = 2000;
if (rsonReader.GetMember(GAME_TIME_KEY, &valueReader))
{
RsonReader timeReader;
int timeValue;
if (valueReader.GetMember(GAME_TIME_HOUR, &timeReader))
{
if (timeReader.AsInt(timeValue))
{
m_GameTimeHour = timeValue;
}
}
if (valueReader.GetMember(GAME_TIME_MINUTE, &timeReader))
{
if (timeReader.AsInt(timeValue))
{
m_GameTimeMinute = timeValue;
}
}
if (valueReader.GetMember(GAME_TIME_SECOND, &timeReader))
{
if (timeReader.AsInt(timeValue))
{
m_GameTimeSecond = timeValue;
}
}
if (valueReader.GetMember(GAME_TIME_DAY, &timeReader))
{
if (timeReader.AsInt(timeValue))
{
m_GameTimeDayOfMonth = timeValue;
}
}
if (valueReader.GetMember(GAME_TIME_MONTH, &timeReader))
{
if (timeReader.AsInt(timeValue))
{
m_GameTimeMonth = timeValue;
}
}
if (valueReader.GetMember(GAME_TIME_YEAR, &timeReader))
{
if (timeReader.AsInt(timeValue))
{
m_GameTimeYear = timeValue;
}
}
}
m_PosixCreationTime = 0;
if (rsonReader.GetMember(POSIX_CREATION_TIME_KEY, &valueReader))
{
s32 signedTime = 0;
valueReader.AsInt(signedTime);
m_PosixCreationTime = (u32) signedTime;
}
m_ArenaTheme = 0;
if (rsonReader.GetMember(ARENA_THEME_INDEX_KEY, &valueReader))
{
valueReader.AsUns(m_ArenaTheme);
}
m_ArenaVariation = 0;
if (rsonReader.GetMember(ARENA_VARIATION_INDEX_KEY, &valueReader))
{
valueReader.AsUns(m_ArenaVariation);
}
#if PHOTO_METADATA_STORES_WIDESCREEN_FLAG
m_bIsWidescreen = true;
if (rsonReader.GetMember(WIDESCREEN_KEY, &valueReader))
{
valueReader.AsBool(m_bIsWidescreen);
}
#endif // PHOTO_METADATA_STORES_WIDESCREEN_FLAG
#if PHOTO_METADATA_STORES_SELFIE_FLAG
m_bIsSelfie = false;
if (rsonReader.GetMember(SELFIE_KEY, &valueReader))
{
valueReader.AsBool(m_bIsSelfie);
}
#endif // PHOTO_METADATA_STORES_SELFIE_FLAG
m_bIsInDirectorMode = false;
if (rsonReader.GetMember(DIRECTOR_KEY, &valueReader))
{
valueReader.AsBool(m_bIsInDirectorMode);
}
m_bTakenInRockstarEditor = false;
if (rsonReader.GetMember(ROCKSTAR_EDITOR_KEY, &valueReader))
{
valueReader.AsBool(m_bTakenInRockstarEditor);
}
m_bOnIslandX = false;
if (rsonReader.GetMember(ON_ISLAND_X_KEY, &valueReader))
{
valueReader.AsBool(m_bOnIslandX);
}
m_Akamai = false;
if (rsonReader.GetMember(AKAMAI_KEY, &valueReader))
{
valueReader.AsBool(m_Akamai);
}
m_ImageSignature = 0;
if (rsonReader.GetMember(IMAGE_SIGNATURE_KEY, &valueReader))
{
valueReader.AsUns64(m_ImageSignature);
}
#if PHOTO_METADATA_STORES_NEARBY_VEHICLES
ReadVehiclesFromJson(rsonReader);
#endif // PHOTO_METADATA_STORES_NEARBY_VEHICLES
#if PHOTO_METADATA_STORES_NEARBY_WEAPONS
ReadWeaponsFromJson(rsonReader);
#endif // PHOTO_METADATA_STORES_NEARBY_WEAPONS
#if PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
ReadGamerTagsFromJson(rsonReader);
#endif // PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
#if PHOTO_METADATA_STORES_NEARBY_SP_CHARS
ReadSinglePlayerCharacterTextLabelsFromJson(rsonReader);
#endif // PHOTO_METADATA_STORES_NEARBY_SP_CHARS
return true;
}
const char *CSavegamePhotoMetadata::GetStringFromGameMode(u8 gameMode) const
{
switch (gameMode)
{
case 0 :
return "SP";
// break;
case 1 :
return "FREEMODE";
// break;
}
return "SP";
}
u8 CSavegamePhotoMetadata::GetGameModeFromString(const char *pGameModeString) const
{
if (stricmp(pGameModeString, "FREEMODE") == 0)
{
return 1;
}
return 0;
}
#if __BANK
// Add the lengths of all atStrings to the sizeof(CSavegamePhotoMetadata)
u32 CSavegamePhotoMetadata::GetSize() const
{
u32 returnSize = sizeof(CSavegamePhotoMetadata);
returnSize += m_AreaNameTextKey.GetLength();
returnSize += m_SinglePlayerMissionName.GetLength();
returnSize += m_RadioStationName.GetLength();
returnSize += m_UgcID.GetLength();
return returnSize;
}
void CSavegamePhotoMetadata::UpdateDebug()
{
if (sm_bDisplayBoundingRectanglesForPeds)
{
CPlayerInfo* pPlayerInfo = CGameWorld::GetMainPlayerInfo();
CPed *pPlayerPed = pPlayerInfo ? pPlayerInfo->GetPlayerPed() : NULL;
if (pPlayerPed)
{
CEntityScannerIterator pedIterator = pPlayerPed->GetPedIntelligence()->GetNearbyPeds();
CEntity* pEntity = pedIterator.GetFirst();
while(pEntity)
{
IsEntityVisible(pEntity, true);
pEntity = pedIterator.GetNext();
}
} // if (pPlayerPed)
}
}
#endif // __BANK
void CSavegamePhotoMetadata::GetNormalisedScreenCoordFromWorldCoord(const Vector3 &vecWorldPos, float &NormalisedX, float &NormalisedY)
{
const grcViewport *pCurrentGrcViewport = gVpMan.GetCurrentGameGrcViewport();
float fWindowX = 0.0f, fWindowY = 0.0f;
pCurrentGrcViewport->Transform(RCC_VEC3V(vecWorldPos), fWindowX, fWindowY);
fWindowX=( fWindowX*grcViewport::GetDefaultScreen()->GetWidth() ) /pCurrentGrcViewport->GetWidth();
fWindowY=( fWindowY*grcViewport::GetDefaultScreen()->GetHeight() ) /pCurrentGrcViewport->GetHeight();
NormalisedX = fWindowX / pCurrentGrcViewport->GetWidth();
NormalisedY = fWindowY / pCurrentGrcViewport->GetHeight();
if (NormalisedX < 0.0f)
{
NormalisedX = 0.0f;
}
if (NormalisedX > 1.0f)
{
NormalisedX = 1.0f;
}
if (NormalisedY < 0.0f)
{
NormalisedY = 0.0f;
}
if (NormalisedY > 1.0f)
{
NormalisedY = 1.0f;
}
}
void CSavegamePhotoMetadata::UpdateLimitsOfRectangle(const Vector3 &vecWorldPos, float &MinX, float &MinY, float &MaxX, float &MaxY)
{
float normalisedX = 0.0f;
float normalisedY = 0.0f;
GetNormalisedScreenCoordFromWorldCoord(vecWorldPos, normalisedX, normalisedY);
if (normalisedX < MinX)
{
MinX = normalisedX;
}
if (normalisedX > MaxX)
{
MaxX = normalisedX;
}
if (normalisedY < MinY)
{
MinY = normalisedY;
}
if (normalisedY > MaxY)
{
MaxY = normalisedY;
}
}
float CSavegamePhotoMetadata::GetScreenAreaOfBoundingBox(const spdAABB &aabb, bool BANK_ONLY(bDisplayBoundingRectangle))
{
float screenArea = 0.0f;
const Vector3 vMin = VEC3V_TO_VECTOR3(aabb.GetMin());
const Vector3 vMax = VEC3V_TO_VECTOR3(aabb.GetMax());
float fBoxMinX = 1.0f;
float fBoxMaxX = 0.0f;
float fBoxMinY = 1.0f;
float fBoxMaxY = 0.0f;
Vector3 vCorners[8] = {
Vector3(vMin.x, vMin.y, vMin.z), Vector3(vMax.x, vMin.y, vMin.z), Vector3(vMax.x, vMax.y, vMin.z), Vector3(vMin.x, vMax.y, vMin.z),
Vector3(vMin.x, vMin.y, vMax.z), Vector3(vMax.x, vMin.y, vMax.z), Vector3(vMax.x, vMax.y, vMax.z), Vector3(vMin.x, vMax.y, vMax.z)
};
for(u32 v=0; v<8; v++)
{
UpdateLimitsOfRectangle(vCorners[v], fBoxMinX, fBoxMinY, fBoxMaxX, fBoxMaxY);
}
if ( (fBoxMinX < 1.0f) && (fBoxMaxX > 0.0f) && (fBoxMinY < 1.0f) && (fBoxMaxY > 0.0f) )
{
screenArea = (fBoxMaxX - fBoxMinX) * (fBoxMaxY - fBoxMinY);
#if __BANK
if (bDisplayBoundingRectangle)
{
grcDebugDraw::Quad(Vec2V(fBoxMinX, fBoxMinY), Vec2V(fBoxMinX, fBoxMaxY), Vec2V(fBoxMaxX, fBoxMaxY), Vec2V(fBoxMaxX, fBoxMinY), Color32(1.0f, 0.0f, 0.0f, 0.5f), false);
}
#endif // __BANK
}
return screenArea;
}
bool CSavegamePhotoMetadata::IsEntityVisible(CEntity *pEntity, bool bDisplayDebug)
{
const float fMinimumScreenAreaForPeds = 0.001f; // // This seemed a reasonable figure when I tested the player ped. If we need to deal with vehicles then I'll probably need a separate number for them.
if (pEntity->GetIsVisible())
{
spdAABB tempBox;
const spdAABB &aabb = pEntity->GetBoundBox( tempBox );
if (COcclusion::IsBoxVisible( aabb ))
{
float fScreenArea = GetScreenAreaOfBoundingBox(aabb, bDisplayDebug);
#if __BANK
if (bDisplayDebug)
{
const Vector3 vecEntityPosition = VEC3V_TO_VECTOR3(pEntity->GetTransform().GetPosition());
const Vector3 vecDebugWorldCoors = vecEntityPosition + Vector3(0,0,1.0f);
char debugText[16];
formatf(debugText, 16, "%f", fScreenArea);
grcDebugDraw::Text(vecDebugWorldCoors, Color32(1.0f, 0.0f, 0.0f, 0.5f), debugText);
}
#endif // __BANK
if (fScreenArea > fMinimumScreenAreaForPeds)
{
return true;
}
}
}
return false;
}
#if PHOTO_METADATA_STORES_NEARBY_SP_CHARS
const u32 MAX_LENGTH_OF_TEXT_LABEL_FOR_CHARACTERS_NAME = 16;
// I searched for all ped models beginning with IG_ in model_enums.sch
// These models aren't listed in Initialise_CharSheet_Global_Variables_On_Startup()
// Would I need to add their names to the text files?
// IG_BALLASOG=-1492432238 // Paradise2, Franklin0, Lamar1
// IG_BANKMAN=-1868718465 // finale_heist2A
// IG_BESTMEN=1464257942 // re_stag_do
// IG_BRAD=-1111799518 // Prologue1
// IG_BRIDE=1633872967 // re_hitch_lift and re_stag_do
// IG_CAR3GUY1=-2063996617 // carsteal1
// IG_CAR3GUY2=1975732938 // carsteal1
// IG_CASEY=-520477356 // finale_heist2A
// IG_CHRISFORMAGE=678319271 // only used in multiplayer net_freemode_cut.sch
// IG_CLAY=1825562762 // Trevor1
// IG_CLAYPAIN // Franklin1
// IG_DALE=1182012905 // Not referenced in script
// IG_FABIEN=-795819184 // Family5 and Family6
// IG_FBISUIT_01=988062523 // FBI2
// IG_GROOM=-20018299 // Not referenced in script
// IG_HUNTER=-837606178 // TheLastOne.sc and initial_scenes_TheLastOne.sch
// IG_JANET=225287241 // Chinese1, Chinese2, Minute1
// IG_JAY_NORRIS=2050158196 // Lester1
// IG_JEWELASS=257763003 // jewelry_heist.sc and jewelry_setup1.sc
// IG_JOHNNYKLEBITZ=-2016771922 // Trevor1.sc
// IG_KERRYMCINTOSH=1530648845 // initial_scenes_Nigel.sch
// IG_LIFEINVAD_02=666718676 // Not referenced in script
// IG_MAGENTA=-52653814 // Lamar1
// IG_MICHELLE=-1080659212 // Not referenced in script
// IG_MILTON=-886023758 // carsteal3, Michael4 and Solomon1
// IG_MRK=-304305299 // FBI2 and FBI3
// IG_MRSPHILLIPS=946007720 // Not referenced in script
// IG_NATALIA=-568861381 // Not referenced in script
// IG_OLD_MAN1A=1906124788 // Chinese1, Chinese2, trigger_scene_chinese1.sch and trigger_scene_chinese2.sch
// IG_OLD_MAN2=-283816889 // Chinese1, Chinese2, trigger_scene_chinese1.sch and trigger_scene_chinese2.sch
// IG_ONEIL=768005095 // Not referenced in script
// IG_PAPER=-1717894970 // Michael3 and Michael3_stage_firstarea.sch
// IG_PRIEST=1681385341 // Not referenced in script
// IG_PROLSEC_02=666086773 // Prologue1
// IG_RAMP_GANG=-449965460 // rampagev4_include.sch and initial_scenes_rampage.sch
// IG_RAMP_HIC=1165307954 // rampagev4_include.sch and initial_scenes_rampage.sch
// IG_RAMP_HIPSTER=-554721426 // rampagev4_include.sch and initial_scenes_rampage.sch
// IG_RAMP_MEX=-424905564 // rampagev4_include.sch and initial_scenes_rampage.sch
// IG_ROCCOPELOSI=-709209345 // Solomon1, Solomon2 and trigger_scene_solomon2.sch
// IG_RUSSIANDRUNK=1024089777 // Chinese1 and trigger_scene_chinese1.sch
// IG_SCREEN_WRITER=-1689993 // Not referenced in script
// IG_TALINA=-409745176 // re_crashrescue
// IG_TAOSTRANSLATOR=2089096292 // Chinese1, Chinese2 and trigger_scene_chinese2.sch
// IG_TERRY=1728056212 // Trevor1
// IG_TOMEPSILON=-847807830 // Epsilon6, Epsilon7, epsDesert and initial_scenes_Epsilon.sch
// IG_TONYA=-892841148 // gpb_Tonya, ambient_TonyaCall, ambient_TonyaCall2, ambient_TonyaCall5, Tonya1, Tonya2, Tonya5, initial_scenes_Tonya.sch
// IG_TRAFFICWARDEN=1461287021 // jewelry_heist
// IG_TYLERDIX=1382414087 // Nigel1B and initial_scenes_Nigel.sch
// IG_ZIMBOR=188012277 // Not referenced in script
const char *CSavegamePhotoMetadata::GetTextLabelForPedModel(const CPed *pPed)
{
if (pPed)
{
CBaseModelInfo* pModel = CModelInfo::GetBaseModelInfo(pPed->GetModelId());
if (Verifyf(pModel, "CSavegamePhotoMetadata::GetTextLabelForPedModel - couldn't find model for the ped's model index"))
{
// I copied this data from Steve Taylor's Initialise_CharSheet_Global_Variables_On_Startup() in charsheet_public.sch
switch (pModel->GetHashKey())
{
case 0xD7114C9 : // ( ATSTRINGHASH("PLAYER_ZERO", 0xD7114C9), "CELL_101"); // CHAR_MICHAEL
return "CELL_101";
case 0x9b810fa2 : // ( ATSTRINGHASH("PLAYER_TWO", 0x9b810fa2), "CELL_102"); // CHAR_TREVOR
return "CELL_102";
case 0x9b22dbaf : // ( ATSTRINGHASH("PLAYER_ONE", 0x9b22dbaf), "CELL_103"); // CHAR_FRANKLIN
return "CELL_103";
//Virtual multiplayer character - CHAR_MULTIPLAYER - A_M_Y_BeachVesp_01, "CELL_197"
case 0x4da6e849 : // ( ATSTRINGHASH("IG_LESTERCREST", 0x4da6e849), "CELL_111"); // FBI dude - CHAR_LESTER
return "CELL_111";
// Ask Steve about this one - CHAR_LESTER_DEATHWISH - IG_LESTERCREST, "CELL_E_211" "Lester Deathwish"
case 0x14ec17ea : // ( ATSTRINGHASH("A_C_CHOP", 0x14ec17ea), "CELL_E_225"); // Chop
return "CELL_E_225";
case 0x570462b9 : // ( ATSTRINGHASH("IG_JIMMYDISANTO", 0x570462b9), "CELL_124"); // CHAR_JIMMY
return "CELL_124";
case 0xde352a35 : // ( ATSTRINGHASH("IG_TRACYDISANTO", 0xde352a35), "CELL_125"); // CHAR_TRACEY
return "CELL_125";
case 0x400aec41 : // ( ATSTRINGHASH("IG_ABIGAIL", 0x400aec41), "CELL_E_240"); // CHAR_ABIGAIL
return "CELL_E_240";
case 0x6d1e15f7 : // ( ATSTRINGHASH("IG_AMANDATOWNLEY", 0x6d1e15f7), "CELL_126"); // CHAR_AMANDA
return "CELL_126";
case 0x4c7b2f05 : // ( ATSTRINGHASH("IG_SIEMONYETARIAN", 0x4c7b2f05), "CELL_127"); // CHAR_SIMEON
return "CELL_127";
case 0x65b93076 : // ( ATSTRINGHASH("IG_LAMARDAVIS", 0x65b93076), "CELL_128"); // CHAR_LAMAR
return "CELL_128";
case 0xbd006af1 : // ( ATSTRINGHASH("IG_NERVOUSRON", 0xbd006af1), "CELL_129"); // CHAR_RON
return "CELL_129";
case 0xdc5c5ea5 : // ( ATSTRINGHASH("IG_TAOCHENG", 0xdc5c5ea5), "CELL_133"); // CHAR_CHENG
return "CELL_133";
// Ask if Saeeda has a specific model - CHAR_SAEEDA - IG_TAOCHENG, "CELL_E_281"
case 0x382121c8 : // ( ATSTRINGHASH("IG_STEVEHAINS", 0x382121c8), "CELL_134"); // CHAR_STEVE
return "CELL_134";
case 0x92991b72 : // ( ATSTRINGHASH("IG_WADE", 0x92991b72), "CELL_135"); // CHAR_WADE
return "CELL_135";
case 0xa23b5f57 : // ( ATSTRINGHASH("IG_TENNISCOACH", 0xa23b5f57), "CELL_136"); // CHAR_TENNIS_COACH
return "CELL_136";
case 0x86bdfe26 : // ( ATSTRINGHASH("IG_SOLOMON", 0x86bdfe26), "CELL_137"); // CHAR_SOLOMON
return "CELL_137";
case 0xdfe443e5 : // ( ATSTRINGHASH("IG_LAZLOW", 0xdfe443e5), "CELL_138"); // CHAR_LAZLOW
return "CELL_138";
// CHAR_ESTATE_AGENT - A_M_Y_BUSINESS_01, "CELL_139" - Could an ambient ped use this model and be mistaken for this character?
case 0x7461a0b0 : // ( ATSTRINGHASH("IG_DEVIN", 0x7461a0b0), "CELL_142"); // CHAR_DEVIN
return "CELL_142";
case 0x15cd4c33 : // ( ATSTRINGHASH("IG_DAVENORTON", 0x15cd4c33), "CELL_143"); // CHAR_DAVE
return "CELL_143";
// CHAR_MARTIN - A_M_Y_BUSINESS_01, "CELL_144" - Could an ambient ped use this model and be mistaken for this character?
case 0xb1b196b2 : // ( ATSTRINGHASH("IG_FLOYD", 0xb1b196b2), "CELL_145"); // CHAR_FLOYD
return "CELL_145";
// CHAR_GAYMILITARY - A_M_Y_BUSINESS_01, "CELL_146" - Could an ambient ped use this model and be mistaken for this character?
// CHAR_OSCAR - G_M_Y_MexGoon_02, "CELL_164" - Could an ambient ped use this model and be mistaken for this character?
case 0xaae4ea7b : // ( ATSTRINGHASH("IG_CHENGSR", 0xaae4ea7b), "CELL_200"); // CHAR_CHENGSR
return "CELL_200";
case 0xcbfc0df5 : // ( ATSTRINGHASH("IG_DRFRIEDLANDER", 0xcbfc0df5), "CELL_121"); // CHAR_DR_FRIEDLANDER
return "CELL_121";
case 0x36984358 : // ( ATSTRINGHASH("IG_STRETCH", 0x36984358), "CELL_122"); // CHAR_STRETCH
return "CELL_122";
case 0x26a562b7 : // ( ATSTRINGHASH("IG_ORTEGA", 0x26a562b7), "CELL_123"); // CHAR_ORTEGA
return "CELL_123";
// CHAR_ONEIL - A_M_M_FARMER_01, "CELL_E_208" - Could an ambient ped use this model and be mistaken for this character?
case 0xc56e118c : // ( ATSTRINGHASH("IG_PATRICIA", 0xc56e118c), "CELL_E_210"); // CHAR_PATRICIA
return "CELL_E_210";
case 0x0d810489 : // ( ATSTRINGHASH("IG_TANISHA", 0x0d810489), "CELL_E_218"); // CHAR_TANISHA
return "CELL_E_218";
case 0x820b33bd : // ( ATSTRINGHASH("IG_DENISE", 0x820b33bd), "CELL_E_226"); // CHAR_DENISE
return "CELL_E_226";
case 0xaf03dde1 : // ( ATSTRINGHASH("IG_MOLLY", 0xaf03dde1), "CELL_E_227"); // CHAR_MOLLY
return "CELL_E_227";
case 0x5389a93c : // ( ATSTRINGHASH("IG_LIFEINVAD_01", 0x5389a93c), "CELL_E_217"); // CHAR_RICKIE
return "CELL_E_217";
case 0x49eadbf6 : // ( ATSTRINGHASH("IG_CHEF", 0x49eadbf6), "CELL_E_224"); // CHAR_CHEF
return "CELL_E_224";
//Random Characters.
case 0x2f8845a3 : // ( ATSTRINGHASH("IG_BARRY", 0x2f8845a3), "CELL_147"); // CHAR_BARRY
return "CELL_147";
case 0xbda21e5c : // ( ATSTRINGHASH("IG_BEVERLY", 0xbda21e5c), "CELL_148"); // CHAR_BEVERLY
return "CELL_148";
// CHAR_BLIMP - IG_BEVERLY, "CELL_E_279"
// CHAR_CRIS - S_M_M_HIGHSEC_01, "CELL_166" - Could an ambient ped use this model and be mistaken for this character?
case 0x9c2db088 : // ( ATSTRINGHASH("IG_DOM", 0x9c2db088), "CELL_150"); // CHAR_DOM
return "CELL_150";
case 0x65978363 : // ( ATSTRINGHASH("IG_HAO", 0x65978363), "CELL_E_246"); // CHAR_HAO
return "CELL_E_246";
case 0xe6631195 : // ( ATSTRINGHASH("IG_CLETUS", 0xe6631195), "CELL_167"); // Known as "Cletus" - CHAR_HUNTER
return "CELL_167";
case 0xeda0082d : // ( ATSTRINGHASH("IG_JIMMYBOSTON", 0xeda0082d), "CELL_151"); // CHAR_JIMMY_BOSTON
return "CELL_151";
case 0xbe204c9b : // ( ATSTRINGHASH("IG_JOEMINUTEMAN", 0xbe204c9b), "CELL_152"); // CHAR_JOE
return "CELL_152";
case 0xe11a9fb4 : // ( ATSTRINGHASH("IG_JOSEF", 0xe11a9fb4), "CELL_153"); // CHAR_JOSEF
return "CELL_153";
case 0x799e9eee : // ( ATSTRINGHASH("IG_JOSH", 0x799e9eee), "CELL_154"); // CHAR_JOSH
return "CELL_154";
case 0xfd418e10 : // ( ATSTRINGHASH("IG_MANUEL", 0xfd418e10), "CELL_156"); // CHAR_MANUEL
return "CELL_156";
case 0x188232d0 : // ( ATSTRINGHASH("IG_MARNIE", 0x188232d0), "CELL_157"); // CHAR_MARNIE
return "CELL_157";
case 0xa36f9806 : // ( ATSTRINGHASH("IG_MARYANN", 0xa36f9806), "CELL_158"); // CHAR_MARY_ANN
return "CELL_158";
case 0x3be8287e : // ( ATSTRINGHASH("IG_MAUDE", 0x3be8287e), "CELL_E_244"); // CHAR_MAUDE
return "CELL_E_244";
case 0x1e04a96b : // ( ATSTRINGHASH("IG_MRS_THORNHILL", 0x1e04a96b), "CELL_161"); // CHAR_MRS_THORNHILL
return "CELL_161";
case 0xc8b7167d : // ( ATSTRINGHASH("IG_NIGEL", 0xc8b7167d), "CELL_162"); // CHAR_NIGEL
return "CELL_162";
case 0x61d4c771 : // ( ATSTRINGHASH("IG_ORLEANS", 0x61d4c771), "CELL_168"); // CHAR_SASQUATCH
return "CELL_168";
case 0x7ef440db : // ( ATSTRINGHASH("IG_ASHLEY", 0x7ef440db), "CELL_E_202"); // CHAR_ASHLEY
return "CELL_E_202";
case 0x47e4eea0 : // ( ATSTRINGHASH("IG_ANDREAS", 0x47e4eea0), "CELL_E_205"); // CHAR_ANDREAS
return "CELL_E_205";
case 0xda890932 : // ( ATSTRINGHASH("IG_DREYFUSS", 0xda890932), "CELL_E_206"); // CHAR_DREYFUSS
return "CELL_E_206";
case 0x60e6a7d8 : // ( ATSTRINGHASH("IG_OMEGA", 0x60e6a7d8), "CELL_E_207"); // CHAR_OMEGA
return "CELL_E_207";
// Could an ambient ped use one of these models and be mistaken for one of these characters?
// CHAR_DOMESTIC_GIRL - A_M_Y_BeachVesp_01, "CELL_140"
//Now known as Ursula - CHAR_HITCHER_GIRL - A_F_Y_HIKER_01, "CELL_141"
// CHAR_MECHANIC - S_M_Y_XMECH_02, "CELL_180"
// How can we differentiate the stripper models
// CHAR_STRIPPER_JULIET - S_F_Y_STRIPPER_01, "CELL_112"
// CHAR_STRIPPER_NIKKI - S_F_Y_STRIPPER_02, "CELL_113"
// CHAR_STRIPPER_CHASTITY - S_F_Y_STRIPPER_01, "CELL_114"
// CHAR_STRIPPER_CHEETAH - S_F_Y_STRIPPER_02, "CELL_115"
// CHAR_STRIPPER_SAPPHIRE - S_F_Y_STRIPPER_01, "CELL_116"
// CHAR_STRIPPER_INFERNUS - S_F_Y_STRIPPER_02, "CELL_117"
// CHAR_STRIPPER_FUFU - S_F_Y_STRIPPER_01, "CELL_118"
// CHAR_STRIPPER_PEACH - S_F_Y_STRIPPER_02, "CELL_119"
// Could an ambient ped use one of these models and be mistaken for one of these characters?
// CHAR_BROKEN_DOWN_GIRL - A_F_Y_Fitness_02, "CELL_120"
// CHAR_ANTONIA - A_F_Y_Hipster_01, "CELL_E_280"
// CHAR_TAXI_LIZ - A_F_Y_EASTSA_03, "CELL_E_201"
// Towing ped, Tonya // CHAR_TOW_TONYA - A_F_M_FatBla_01, "CELL_E_223"
// The following peds all use the same model. Are they never seen? Do they only speak on the phone?
//Special Number - see bug 1020339
// CHAR_LS_CUSTOMS - A_M_Y_BeachVesp_01, "CELL_E_209"
// CHAR_AMMUNATION - A_M_Y_BeachVesp_01, "CELL_E_220"
//MP Contacts
// ...bosses
// Lost: Al Carter (which is also the name of the Lost Mechanic so slight discrepency there)
// CHAR_MP_BIKER_BOSS - A_M_Y_BeachVesp_01, "CELL_174"
// CHAR_MP_FAM_BOSS - A_M_Y_BeachVesp_01, "CELL_176"
// Vagos: Edgar Claros // CHAR_MP_MEX_BOSS - A_M_Y_BeachVesp_01, "CELL_177"
// CHAR_MP_PROF_BOSS - A_M_Y_BeachVesp_01, "CELL_178"
// ...lieutenants
// CHAR_MP_MEX_LT - A_M_Y_BeachVesp_01, "CELL_E_204"
// ...car mechanic contacts
// CHAR_MP_BIKER_MECHANIC - A_M_Y_BeachVesp_01, "CELL_173"
// ...docks contacts
// CHAR_MP_MEX_DOCKS - A_M_Y_BeachVesp_01, "CELL_165"
// CHAR_MP_STRETCH - A_M_Y_BeachVesp_01, "CELL_172"
// MP Freemode
// ...general contact (used in intro)
// CHAR_MP_FM_CONTACT - A_M_Y_BeachVesp_01, "CELL_E_215"
// ...brucie (used as a special ability contact)
// CHAR_MP_BRUCIE - A_M_Y_BeachVesp_01, "CELL_E_216"
// ...merryweather (used as a special ability contact)
// CHAR_MP_MERRYWEATHER - A_M_Y_BeachVesp_01, "CELL_E_221"
// ...gerald (used as a Contact Mission contact)
// CHAR_MP_GERALD - A_M_Y_BeachVesp_01, "CELL_E_228"
// ...mechanic (used as a special ability contact) //Los Santos Customs at present.
// CHAR_MP_MECHANIC - A_M_Y_BeachVesp_01, "CELL_E_MP0"
// ...Julio Fabrizio
// CHAR_MP_JULIO - A_M_Y_BeachVesp_01, "CELL_E_242"
// ...Strip Club PR //Listed as promotion@V-Unicorn.
// CHAR_MP_STRIPCLUB_PR - A_M_Y_BeachVesp_01, "CELL_E_243"
// ...snitches
// KGM 28/3/12: Generic MP Snitch - Corey Parker
// CHAR_MP_SNITCH - A_M_Y_BeachVesp_01, "CELL_169"
// ...other mission flow contacts
// CHAR_MP_FIB_CONTACT - A_M_Y_BeachVesp_01, "CELL_184"
// CHAR_MP_ARMY_CONTACT - A_M_Y_BeachVesp_01, "CELL_185"
//Pegasus vehicle delivery service - see bug #1300310
// CHAR_PEGASUS_DELIVERY - A_M_Y_BeachVesp_01, "CELL_E_247"
// CHAR_LIFEINVADER - A_M_Y_BeachVesp_01, "CELL_E_276"
// ...special characters for MP missions
// CHAR_MP_ROBERTO - A_M_Y_BeachVesp_01, "CELL_182"
// CHAR_MP_RAY_LAVOY - A_M_Y_BeachVesp_01, "CELL_183"
} // switch (pModel->GetHashKey())
} // if (Verifyf(pModel
} // if (pPed)
return "";
}
void CSavegamePhotoMetadata::AddPedToSinglePlayerCharacterArray(CPed *pPed, s32 &number_of_single_player_characters)
{
const char *pTextLabelOfCharacterName = GetTextLabelForPedModel(pPed);
if (strlen(pTextLabelOfCharacterName) > 0)
{
if (number_of_single_player_characters < MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS)
{
atString characterNameTextLabel(pTextLabelOfCharacterName);
m_AtArrayOfSinglePlayerCharacters.PushAndGrow(characterNameTextLabel, 1);
number_of_single_player_characters++;
}
}
}
void CSavegamePhotoMetadata::WriteSinglePlayerCharacterTextLabelsToJson(RsonWriter &rsonWriter, bool &bSuccess) const
{
if (bSuccess)
{
char arrayOfCharacterNames[MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS][MAX_LENGTH_OF_TEXT_LABEL_FOR_CHARACTERS_NAME];
const u32 sizeOfCharacterNameArray = m_AtArrayOfSinglePlayerCharacters.GetCount();
u32 number_of_visible_single_player_characters = 0;
for (u32 characterNameLoop = 0; characterNameLoop < sizeOfCharacterNameArray; characterNameLoop++)
{
if (m_AtArrayOfSinglePlayerCharacters[characterNameLoop].GetLength() != 0)
{
safecpy(arrayOfCharacterNames[number_of_visible_single_player_characters], m_AtArrayOfSinglePlayerCharacters[characterNameLoop].c_str(), MAX_LENGTH_OF_TEXT_LABEL_FOR_CHARACTERS_NAME);
number_of_visible_single_player_characters++;
}
}
if (number_of_visible_single_player_characters > 0)
{
bSuccess = rsonWriter.WriteArray(SINGLE_PLAYER_CHARACTERS_KEY, arrayOfCharacterNames, number_of_visible_single_player_characters);
}
}
}
void CSavegamePhotoMetadata::ReadSinglePlayerCharacterTextLabelsFromJson(RsonReader &rsonReader)
{
RsonReader valueReader;
u32 loop = 0;
m_AtArrayOfSinglePlayerCharacters.Reset();
if (rsonReader.GetMember(SINGLE_PLAYER_CHARACTERS_KEY, &valueReader))
{
char arrayOfCharacterNames[MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS][MAX_LENGTH_OF_TEXT_LABEL_FOR_CHARACTERS_NAME];
for (loop = 0; loop < MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS; loop++)
{
safecpy(arrayOfCharacterNames[loop], "", MAX_LENGTH_OF_TEXT_LABEL_FOR_CHARACTERS_NAME);
}
// AsArray returns the number of entries that have been read
valueReader.AsArray(arrayOfCharacterNames, MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS);
u32 number_of_character_text_labels_read_from_json = 0;
for (loop = 0; loop < MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS; loop++)
{
if (arrayOfCharacterNames[loop][0] != '\0')
{
number_of_character_text_labels_read_from_json++;
}
}
if (number_of_character_text_labels_read_from_json > 0)
{
m_AtArrayOfSinglePlayerCharacters.Reserve(number_of_character_text_labels_read_from_json);
for (loop = 0; loop < MAX_NUM_VISIBLE_SINGLE_PLAYER_CHARACTERS; loop++)
{
if (arrayOfCharacterNames[loop][0] != '\0')
{
m_AtArrayOfSinglePlayerCharacters.Append() = arrayOfCharacterNames[loop];
}
}
}
}
#if __DEV
const u32 sizeOfTextLabelArray = m_AtArrayOfSinglePlayerCharacters.GetCount();
for (loop = 0; loop < sizeOfTextLabelArray; loop++)
{
photoDisplayf("CSavegamePhotoMetadata::ReadSinglePlayerCharacterTextLabelsFromJson - names of visible single player characters - array element %u has name %s", loop, TheText.Get(m_AtArrayOfSinglePlayerCharacters[loop]));
}
#endif // __DEV
}
#endif // PHOTO_METADATA_STORES_NEARBY_SP_CHARS
#if PHOTO_METADATA_STORES_NEARBY_WEAPONS
const u32 hashForInvalidWeapon = ATSTRINGHASH("WT_INVALID", 0xbfed8500);
void CSavegamePhotoMetadata::AddPedWeaponToArray(CPed *pPed, s32 &number_of_visible_weapons)
{
if (number_of_visible_weapons < MAX_NUM_VISIBLE_WEAPONS)
{
if (pPed->GetWeaponManager())
{
if (pPed->GetWeaponManager()->GetEquippedWeaponObjectHash())
{
if (pPed->GetWeaponManager()->GetEquippedWeaponInfo())
{
// m_ArrayOfVisibleWeapons[number_of_visible_weapons] = pPed->GetWeaponManager()->GetEquippedWeaponObjectHash();
u32 humanNameHash = pPed->GetWeaponManager()->GetEquippedWeaponInfo()->GetHumanNameHash();
if ( (humanNameHash != hashForInvalidWeapon) && (TheText.DoesTextLabelExist(humanNameHash)) )
{
m_AtArrayOfVisibleWeapons.PushAndGrow(humanNameHash, 1);
photoDisplayf("CSavegamePhotoMetadata::AddPedWeaponToArray - visible equipped weapons - array element %d has name %s", number_of_visible_weapons, TheText.Get(humanNameHash, "weapon in photo"));
number_of_visible_weapons++;
}
else
{
photoDisplayf("CSavegamePhotoMetadata::AddPedWeaponToArray - visible equipped weapons - equipped weapon with model hash %u doesn't have a valid entry in the language file", pPed->GetWeaponManager()->GetEquippedWeaponInfo()->GetModelHash());
}
}
}
}
}
}
void CSavegamePhotoMetadata::WriteWeaponsToJson(RsonWriter &rsonWriter, bool &bSuccess) const
{
// Array of hashes of weapons equipped by visible peds
if (bSuccess)
{
if (m_AtArrayOfVisibleWeapons.GetCount() > 0)
{
u32 arrayOfWeaponsToWrite[MAX_NUM_VISIBLE_WEAPONS];
const u32 numberOfVisibleWeapons = m_AtArrayOfVisibleWeapons.GetCount();
for (u32 weaponCopyLoop = 0; weaponCopyLoop < numberOfVisibleWeapons; weaponCopyLoop++)
{
arrayOfWeaponsToWrite[weaponCopyLoop] = m_AtArrayOfVisibleWeapons[weaponCopyLoop];
}
bSuccess = rsonWriter.WriteArray(WEAPON_HASH_ARRAY_KEY, arrayOfWeaponsToWrite, numberOfVisibleWeapons);
}
}
}
void CSavegamePhotoMetadata::ReadWeaponsFromJson(RsonReader &rsonReader)
{
RsonReader valueReader;
u32 loop = 0;
// Array of hashes of weapons equipped by visible peds
m_AtArrayOfVisibleWeapons.Reset();
if (rsonReader.GetMember(WEAPON_HASH_ARRAY_KEY, &valueReader))
{
u32 arrayOfWeaponsToRead[MAX_NUM_VISIBLE_WEAPONS];
for (loop = 0; loop < MAX_NUM_VISIBLE_WEAPONS; loop++)
{
arrayOfWeaponsToRead[loop] = 0;
}
// AsArray returns the number of entries that have been read
valueReader.AsArray(arrayOfWeaponsToRead, MAX_NUM_VISIBLE_WEAPONS);
u32 number_of_visible_weapons_read_from_json = 0;
for (loop = 0; loop < MAX_NUM_VISIBLE_WEAPONS; loop++)
{
if (arrayOfWeaponsToRead[loop] != 0)
{
number_of_visible_weapons_read_from_json++;
}
}
if (number_of_visible_weapons_read_from_json > 0)
{
m_AtArrayOfVisibleWeapons.Reserve(number_of_visible_weapons_read_from_json);
for (loop = 0; loop < MAX_NUM_VISIBLE_WEAPONS; loop++)
{
if (arrayOfWeaponsToRead[loop] != 0)
{
m_AtArrayOfVisibleWeapons.Append() = arrayOfWeaponsToRead[loop];
}
}
}
}
#if __DEV
const u32 sizeOfWeaponArray = m_AtArrayOfVisibleWeapons.GetCount();
for (loop = 0; loop < sizeOfWeaponArray; loop++)
{
photoDisplayf("CSavegamePhotoMetadata::ReadWeaponsFromJson - visible equipped weapons - array element %u has name %s", loop, TheText.Get(m_AtArrayOfVisibleWeapons[loop], "weapon in photo"));
}
#endif // __DEV
}
#endif // PHOTO_METADATA_STORES_NEARBY_WEAPONS
#if PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
void CSavegamePhotoMetadata::AddPedToGamerTagArray(CPed *pPed, s32 &number_of_visible_players)
{
if (pPed->IsPlayer())
{
// Or could I get the gamer tag using this?
// pPed->GetPlayerInfo()->m_GamerInfo.GetName()
if (pPed->GetNetworkObject())
{
if (pPed->GetNetworkObject()->GetPlayerOwner())
{
if (pPed->GetNetworkObject()->GetPlayerOwner()->GetGamerInfo().GetName())
{
if (number_of_visible_players < MAX_NUM_VISIBLE_PLAYERS)
{
// If I need to write XUIDs on 360, it looks like I can do this GetGamerInfo().GetGamerHandle().GetXuid(). That will return a u64
char tempGamerTag[RLROS_MAX_USERID_SIZE];
pPed->GetNetworkObject()->GetPlayerOwner()->GetGamerInfo().GetGamerHandle().ToUserId(tempGamerTag, sizeof(tempGamerTag));
atString gamerTag(tempGamerTag);
m_AtArrayOfGamerTags.PushAndGrow(gamerTag, 1);
number_of_visible_players++;
}
}
}
}
}
}
void CSavegamePhotoMetadata::WriteGamerTagsToJson(RsonWriter &rsonWriter, bool &bSuccess) const
{
if (bSuccess)
{
char arrayOfGamerTags[MAX_NUM_VISIBLE_PLAYERS][RLROS_MAX_USERID_SIZE];
const u32 sizeOfGamerTagArray = m_AtArrayOfGamerTags.GetCount();
u32 number_of_visible_players = 0;
for (u32 gamerTagLoop = 0; gamerTagLoop < sizeOfGamerTagArray; gamerTagLoop++)
{
if (m_AtArrayOfGamerTags[gamerTagLoop].GetLength() != 0)
{
safecpy(arrayOfGamerTags[number_of_visible_players], m_AtArrayOfGamerTags[gamerTagLoop].c_str(), RLROS_MAX_USERID_SIZE);
number_of_visible_players++;
}
}
if (number_of_visible_players > 0)
{
bSuccess = rsonWriter.WriteArray(GAMERTAG_ARRAY_KEY, arrayOfGamerTags, number_of_visible_players);
}
}
}
void CSavegamePhotoMetadata::ReadGamerTagsFromJson(RsonReader &rsonReader)
{
RsonReader valueReader;
u32 loop = 0;
m_AtArrayOfGamerTags.Reset();
if (rsonReader.GetMember(GAMERTAG_ARRAY_KEY, &valueReader))
{
char arrayOfGamerTags[MAX_NUM_VISIBLE_PLAYERS][RLROS_MAX_USERID_SIZE];
for (loop = 0; loop < MAX_NUM_VISIBLE_PLAYERS; loop++)
{
safecpy(arrayOfGamerTags[loop], "", RLROS_MAX_USERID_SIZE);
}
// AsArray returns the number of entries that have been read
valueReader.AsArray(arrayOfGamerTags, MAX_NUM_VISIBLE_PLAYERS);
u32 number_of_gamer_tags_read_from_json = 0;
for (loop = 0; loop < MAX_NUM_VISIBLE_PLAYERS; loop++)
{
if (arrayOfGamerTags[loop][0] != '\0')
{
number_of_gamer_tags_read_from_json++;
}
}
if (number_of_gamer_tags_read_from_json > 0)
{
m_AtArrayOfGamerTags.Reserve(number_of_gamer_tags_read_from_json);
for (loop = 0; loop < MAX_NUM_VISIBLE_PLAYERS; loop++)
{
if (arrayOfGamerTags[loop][0] != '\0')
{
m_AtArrayOfGamerTags.Append() = arrayOfGamerTags[loop];
}
}
}
}
#if __DEV
const u32 sizeOfGamerTagArray = m_AtArrayOfGamerTags.GetCount();
for (loop = 0; loop < sizeOfGamerTagArray; loop++)
{
photoDisplayf("CSavegamePhotoMetadata::ReadGamerTagsFromJson - gamertags of visible players - array element %u has gamertag %s", loop, m_AtArrayOfGamerTags[loop].c_str());
}
#endif // __DEV
}
#endif // PHOTO_METADATA_STORES_NEARBY_MP_GAMERTAGS
#if PHOTO_METADATA_STORES_NEARBY_VEHICLES
void CSavegamePhotoMetadata::AddNearbyVehiclesToArrayOfVisibleVehicles(CPed *pPlayerPed)
{
s32 number_of_visible_vehicles = 0;
CEntityScannerIterator vehicleIterator = pPlayerPed->GetPedIntelligence()->GetNearbyVehicles();
CEntity* pEntity = vehicleIterator.GetFirst();
while(pEntity && (number_of_visible_vehicles < MAX_NUM_VISIBLE_VEHICLES))
{
if (IsEntityVisible(pEntity, false))
{
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(pEntity->GetModelId());
if (photoVerifyf(pModelInfo, "CSavegamePhotoMetadata::AddNearbyVehiclesToArrayOfVisibleVehicles - couldn't find model for the vehicle's model index"))
{
if (pModelInfo->GetModelType() == MI_TYPE_VEHICLE)
{
u32 hashOfVehicleName = atStringHash( ((CVehicleModelInfo*) pModelInfo)->GetGameName() );
m_AtArrayOfVisibleVehicles.PushAndGrow(hashOfVehicleName, 1);
photoDisplayf("CSavegamePhotoMetadata::AddNearbyVehiclesToArrayOfVisibleVehicles - visible vehicles - array element %d has human name %s", number_of_visible_vehicles, TheText.Get(hashOfVehicleName, "vehicle in photo"));
number_of_visible_vehicles++;
}
}
}
pEntity = vehicleIterator.GetNext();
}
}
void CSavegamePhotoMetadata::WriteVehiclesToJson(RsonWriter &rsonWriter, bool &bSuccess) const
{
// Array of hashes of model names of visible vehicles
if (bSuccess)
{
if (m_AtArrayOfVisibleVehicles.GetCount() > 0)
{
u32 arrayOfVehiclesToWrite[MAX_NUM_VISIBLE_VEHICLES];
const u32 numberOfVisibleVehicles = m_AtArrayOfVisibleVehicles.GetCount();
for (u32 vehicleCopyLoop = 0; vehicleCopyLoop < numberOfVisibleVehicles; vehicleCopyLoop++)
{
arrayOfVehiclesToWrite[vehicleCopyLoop] = m_AtArrayOfVisibleVehicles[vehicleCopyLoop];
}
bSuccess = rsonWriter.WriteArray(VEHICLE_MODELS_KEY, arrayOfVehiclesToWrite, numberOfVisibleVehicles);
}
}
}
void CSavegamePhotoMetadata::ReadVehiclesFromJson(RsonReader &rsonReader)
{
RsonReader valueReader;
u32 loop = 0;
// Array of hashes of model names of visible vehicles
m_AtArrayOfVisibleVehicles.Reset();
if (rsonReader.GetMember(VEHICLE_MODELS_KEY, &valueReader))
{
u32 arrayOfVehiclesToRead[MAX_NUM_VISIBLE_VEHICLES];
for (loop = 0; loop < MAX_NUM_VISIBLE_VEHICLES; loop++)
{
arrayOfVehiclesToRead[loop] = 0;
}
// AsArray returns the number of entries that have been read
valueReader.AsArray(arrayOfVehiclesToRead, MAX_NUM_VISIBLE_VEHICLES);
u32 number_of_visible_vehicles_read_from_json = 0;
for (loop = 0; loop < MAX_NUM_VISIBLE_VEHICLES; loop++)
{
if (arrayOfVehiclesToRead[loop] != 0)
{
number_of_visible_vehicles_read_from_json++;
}
}
if (number_of_visible_vehicles_read_from_json > 0)
{
m_AtArrayOfVisibleVehicles.Reserve(number_of_visible_vehicles_read_from_json);
for (loop = 0; loop < MAX_NUM_VISIBLE_VEHICLES; loop++)
{
if (arrayOfVehiclesToRead[loop] != 0)
{
m_AtArrayOfVisibleVehicles.Append() = arrayOfVehiclesToRead[loop];
}
}
}
}
#if __DEV
const u32 sizeOfVehicleArray = m_AtArrayOfVisibleVehicles.GetCount();
for (loop = 0; loop < sizeOfVehicleArray; loop++)
{
photoDisplayf("CSavegamePhotoMetadata::ReadVehiclesFromJson - visible vehicles - array element %u has human name %s", loop, TheText.Get(m_AtArrayOfVisibleVehicles[loop], "vehicle in photo"));
}
#endif // __DEV
}
#endif // PHOTO_METADATA_STORES_NEARBY_VEHICLES