1240 lines
34 KiB
C++
1240 lines
34 KiB
C++
//
|
|
// filename: ProfileSettings.cpp
|
|
// description:
|
|
//
|
|
|
|
// --- Include Files ------------------------------------------------------------
|
|
|
|
#include "profilesettings.h"
|
|
|
|
#if __PS3
|
|
#include <np.h>
|
|
#endif
|
|
|
|
#if __XENON
|
|
#include <xonline.h>
|
|
#endif
|
|
|
|
#if __PPU
|
|
// PS3 headers
|
|
#include <cell/error.h>
|
|
#include <sysutil/sysutil_sysparam.h>
|
|
#endif //__PPU
|
|
|
|
#if RSG_ORBIS
|
|
#include <np/np_common.h>
|
|
#endif
|
|
|
|
// Rage headers
|
|
#include "bank/bkmgr.h"
|
|
#include "bank/bank.h"
|
|
#include "string/stringhash.h"
|
|
#include "system/ipc.h"
|
|
#include "system/param.h"
|
|
#include "system/xtl.h"
|
|
#include "system/nelem.h"
|
|
#include "rline/rlgamerinfo.h"
|
|
#include "rline/rlpresence.h"
|
|
#include "fwnet/netchannel.h"
|
|
|
|
// Game headers
|
|
#include "debug/Debug.h"
|
|
#include "frontend/DisplayCalibration.h"
|
|
#include "Frontend/ui_channel.h"
|
|
#include "network/live/livemanager.h"
|
|
#include "Network/Network.h"
|
|
#include "SaveLoad/GenericGameStorage.h"
|
|
#include "SaveLoad/savegame_queue.h"
|
|
#include "fwsys/timer.h"
|
|
#include "peds/PedWeapons/PedTargetEvaluator.h"
|
|
#include "SaveLoad/savegame_new_game_checks.h"
|
|
#include "stats/StatsInterface.h"
|
|
#include "script/script.h"
|
|
|
|
// --- Defines ------------------------------------------------------------------
|
|
|
|
// --- Constants ----------------------------------------------------------------
|
|
|
|
// --- Structure/Class Definitions ----------------------------------------------
|
|
|
|
// --- Globals ------------------------------------------------------------------
|
|
|
|
RAGE_DEFINE_SUBCHANNEL(net, profile_settings, DIAG_SEVERITY_DEBUG3)
|
|
#undef __net_channel
|
|
#define __net_channel net_profile_settings
|
|
|
|
NOSTRIP_XPARAM(uilanguage);
|
|
NOSTRIP_PARAM(ignoreprofile, "Ignore the current profile settings");
|
|
PARAM(ignoreprofilesetting, "Ignore an individual profile settings");
|
|
PARAM(spewheistvalues, "Ignore an individual profile settings");
|
|
|
|
// --- Static Globals -----------------------------------------------------------
|
|
|
|
static rlPresence::Delegate g_PresenceDlgt(CProfileSettings::OnPresenceEvent);
|
|
|
|
#if __XENON
|
|
|
|
#if __BANK
|
|
bool CProfileSettings::sm_bDisplayDebugText = false;
|
|
bool CProfileSettings::sm_bUpdateProfileWhenNavigatingSettingsMenu = true;
|
|
s32 CProfileSettings::sm_MinimumTimeBetweenProfileSaves = (1000*60*5);
|
|
#endif // __BANK
|
|
|
|
static XOVERLAPPED g_overlapped;
|
|
enum {
|
|
XPROFILE_OPTION_VOICE_MUTED_INDEX,
|
|
XPROFILE_OPTION_VOICE_THRU_SPEAKERS_INDEX,
|
|
XPROFILE_OPTION_VOICE_VOLUME_INDEX,
|
|
XPROFILE_OPTION_CONTROLLER_VIBRATION_INDEX,
|
|
XPROFILE_TITLE_SPECIFIC1_INDEX,
|
|
XPROFILE_GAMER_ACTION_AUTO_AIM_INDEX,
|
|
XPROFILE_GAMER_YAXIS_INVERSION_INDEX,
|
|
XPROFILE_GAMER_CONTROL_SENSITIVITY_INDEX,
|
|
XPROFILE_GAMERCARD_REGION_INDEX,
|
|
XPROFILE_NUM_SETTINGS
|
|
};
|
|
static DWORD g_ProfileSettingIds[XPROFILE_NUM_SETTINGS] = {
|
|
XPROFILE_OPTION_VOICE_MUTED,
|
|
XPROFILE_OPTION_VOICE_THRU_SPEAKERS,
|
|
XPROFILE_OPTION_VOICE_VOLUME,
|
|
XPROFILE_OPTION_CONTROLLER_VIBRATION,
|
|
XPROFILE_TITLE_SPECIFIC1,
|
|
XPROFILE_GAMER_ACTION_AUTO_AIM,
|
|
XPROFILE_GAMER_YAXIS_INVERSION,
|
|
XPROFILE_GAMER_CONTROL_SENSITIVITY,
|
|
XPROFILE_GAMERCARD_REGION
|
|
};
|
|
static XUSER_READ_PROFILE_SETTING_RESULT* g_ProfileSettingResults=NULL;
|
|
|
|
#elif USE_PROFILE_SAVEGAME
|
|
|
|
#define TOTAL_NUM_SETTINGS 163
|
|
#define SETTINGS_VERSION 3
|
|
|
|
struct ProfileSettingBuffer
|
|
{
|
|
s32 m_num;
|
|
s32 m_version;
|
|
s32 m_crc;
|
|
CProfileSettings::CustomSetting m_settings[TOTAL_NUM_SETTINGS];
|
|
|
|
int CalculateCrc();
|
|
};
|
|
ProfileSettingBuffer g_ProfileSettingBuffer;
|
|
static char16 g_profileName[12];
|
|
static char g_fileName[12];
|
|
|
|
#elif RSG_PC
|
|
|
|
#define TOTAL_NUM_PC_SETTINGS (205)
|
|
|
|
CProfileSettings::CustomSetting s_PcSettingsToSave[TOTAL_NUM_PC_SETTINGS];
|
|
s32 s_NumberOfPcSettingsToSave = 0;
|
|
|
|
#endif
|
|
|
|
#if __WIN32PC
|
|
#define PC_SETTINGS_FILENAME "pc_settings.bin"
|
|
#define PC_SETTINGS_PATH "user:/" PC_SETTINGS_FILENAME
|
|
#endif
|
|
|
|
#if USE_PROFILE_SAVEGAME
|
|
int ProfileSettingBuffer::CalculateCrc()
|
|
{
|
|
return atDataHash((const char*)&m_settings[0], sizeof(CProfileSettings::CustomSetting)*m_num, 0);
|
|
}
|
|
#endif
|
|
|
|
// --- Static class members -----------------------------------------------------
|
|
|
|
CProfileSettings* CProfileSettings::sm_Instance = NULL;
|
|
|
|
// --- Code ---------------------------------------------------------------------
|
|
|
|
|
|
void CProfileSettings::InitClass()
|
|
{
|
|
#if __XENON
|
|
g_overlapped.hEvent = CreateEvent(NULL, false, false, NULL);
|
|
#endif
|
|
sm_Instance = rage_new CProfileSettings;
|
|
|
|
#if USE_PROFILE_SAVEGAME
|
|
safecpy(g_profileName, "Profile");
|
|
safecpy(g_fileName, "Profile");
|
|
#endif
|
|
|
|
rlPresence::AddDelegate(&g_PresenceDlgt);
|
|
|
|
sm_Instance->Default();
|
|
|
|
// update once to catch if mainplayer is setup
|
|
sm_Instance->UpdateProfileSettings(true);
|
|
}
|
|
|
|
#if RSG_PC
|
|
void CProfileSettings::InitDelegator()
|
|
{
|
|
rlPresence::AddDelegate(&g_PresenceDlgt);
|
|
}
|
|
#endif
|
|
|
|
void CProfileSettings::ShutdownClass()
|
|
{
|
|
delete sm_Instance;
|
|
}
|
|
|
|
#if __BANK && __XENON
|
|
void CProfileSettings::InitWidgets()
|
|
{
|
|
bkBank& bank = BANKMGR.CreateBank("Profile Settings");
|
|
|
|
bank.AddToggle("Display Debug Text", &sm_bDisplayDebugText);
|
|
bank.AddToggle("Update Profile When Navigating Settings Menu", &sm_bUpdateProfileWhenNavigatingSettingsMenu);
|
|
bank.AddSlider("Minimum Time Between Profile Saves", &sm_MinimumTimeBetweenProfileSaves, 0, 300000, 1000);
|
|
}
|
|
#endif // __BANK && __XENON
|
|
|
|
void CProfileSettings::Read(bool personalSettingsOnly)
|
|
{
|
|
// set personal setting only if not in the middle of a read or it is setting it to false
|
|
if((m_readPending == false && m_reading == false) || personalSettingsOnly == false)
|
|
m_personalSettingsOnly = personalSettingsOnly;
|
|
m_readPending = true;
|
|
}
|
|
|
|
void CProfileSettings::Write(bool bForceWrite)
|
|
{
|
|
if (bForceWrite || m_hasChanged)
|
|
{
|
|
m_hasChanged = false;
|
|
m_writePending = true;
|
|
}
|
|
}
|
|
|
|
void CProfileSettings::WriteNow(bool bForceWrite)
|
|
{
|
|
#if USE_PROFILE_SAVEGAME
|
|
if (!m_bDontWriteProfile)
|
|
#endif
|
|
{
|
|
Write(bForceWrite);
|
|
UpdateProfileSettings(true, true);
|
|
}
|
|
}
|
|
|
|
bool CProfileSettings::StartRead()
|
|
{
|
|
bool success = true;
|
|
|
|
#if __XENON
|
|
DWORD status = ERROR_SUCCESS;
|
|
DWORD resultsSize = 0;
|
|
// This example does not initialize the values of all of the needed paramaters.
|
|
// In this first call, explicitly pass in a null pointer and a buffer size
|
|
// of 0. This forces the function to set cbResults to the correct buffer
|
|
// size.
|
|
status = XUserReadProfileSettings(
|
|
0, // title id of zero means this title
|
|
0, // user 0
|
|
XPROFILE_NUM_SETTINGS,
|
|
&g_ProfileSettingIds[0],
|
|
&resultsSize, // Pass in the address of the size variable
|
|
NULL,
|
|
NULL // This example uses the synchronous model
|
|
);
|
|
Assert(status == ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
Printf("CProfileSettings: Need %d\n", resultsSize);
|
|
|
|
// If the function returns ERROR_INSUFFICIENT_BUFFER cbResults has been
|
|
// changed to reflect the size buffer that will be necessary for this call. Use
|
|
// the new size to allocate a buffer of the appropriate size.
|
|
if (ERROR_INSUFFICIENT_BUFFER == status && resultsSize > 0)
|
|
{
|
|
// delete previous buffer if it exists
|
|
if(g_ProfileSettingResults)
|
|
delete[] (char*)g_ProfileSettingResults;
|
|
g_ProfileSettingResults = (XUSER_READ_PROFILE_SETTING_RESULT*)rage_new char[resultsSize];
|
|
|
|
ZeroMemory(g_ProfileSettingResults, resultsSize);
|
|
|
|
// Next, call the function again with the exact same parameters, except
|
|
// this time use the modified buffer size and a pointer to a buffer that
|
|
// matches it.
|
|
status = XUserReadProfileSettings(
|
|
0,
|
|
m_localIndex,
|
|
XPROFILE_NUM_SETTINGS,
|
|
g_ProfileSettingIds,
|
|
&resultsSize,
|
|
g_ProfileSettingResults,
|
|
&g_overlapped
|
|
);
|
|
Assert(status == ERROR_IO_PENDING);
|
|
}
|
|
return true;
|
|
|
|
#elif USE_PROFILE_SAVEGAME
|
|
|
|
#if USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
m_ProfileLoadStructure.Init(m_localIndex, &g_ProfileSettingBuffer, GetSizeOfPSProfileFile());
|
|
#else
|
|
m_ProfileLoadStructure.Init(m_localIndex, GetFilenameOfPSProfile(), &g_ProfileSettingBuffer, GetSizeOfPSProfileFile());
|
|
#endif // USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
|
|
if (!CGenericGameStorage::PushOnToSavegameQueue(&m_ProfileLoadStructure))
|
|
{
|
|
Warningf("CProfileSettings::StartRead - CGenericGameStorage::PushOnToSavegameQueue failed\n");
|
|
success = false;
|
|
}
|
|
#elif RSG_PC
|
|
m_valid = true;
|
|
m_settings.clear();
|
|
|
|
// you need to be signed in to save profile-specific data.
|
|
char fullPath[rgsc::RGSC_MAX_PATH] = {0};
|
|
if(g_rlPc.IsInitialized() && g_rlPc.GetProfileManager()->IsSignedIn())
|
|
{
|
|
if(AssertVerify(SUCCEEDED(g_rlPc.GetFileSystem()->GetTitleProfileDirectory(fullPath, true))))
|
|
{
|
|
safecat(fullPath, PC_SETTINGS_FILENAME);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
safecpy(fullPath, PC_SETTINGS_PATH);
|
|
}
|
|
|
|
fiStream* pStream = ASSET.Open(fullPath, "");
|
|
if (pStream)
|
|
{
|
|
CustomSetting setting;
|
|
while (true)
|
|
{
|
|
size_t read = pStream->Read(&setting, sizeof(CustomSetting));
|
|
if (read == sizeof(CustomSetting))
|
|
{
|
|
m_settings.PushAndGrow(setting);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
pStream->Close();
|
|
}
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
#else
|
|
#error "Profile Settings are not supported in this build"
|
|
#endif
|
|
|
|
#if USE_SETTINGS_MANAGER
|
|
// Load PC settings
|
|
BANK_ONLY(CSettingsManager::UpdateRagData());
|
|
#endif
|
|
|
|
return success;
|
|
}
|
|
|
|
bool CProfileSettings::FinishRead(bool
|
|
#if __XENON || USE_PROFILE_SAVEGAME
|
|
bWait
|
|
#endif
|
|
)
|
|
{
|
|
#if !__FINAL
|
|
int ignoreProfileSetting = INVALID_PROFILE_SETTING;
|
|
PARAM_ignoreprofilesetting.Get(ignoreProfileSetting);
|
|
#endif
|
|
#if __XENON
|
|
DWORD status;
|
|
DWORD result;
|
|
|
|
status = XGetOverlappedResult(&g_overlapped, &result, bWait);
|
|
if(status == ERROR_IO_INCOMPLETE)
|
|
return false;
|
|
if(status == ERROR_SUCCESS)
|
|
{
|
|
m_valid = true;
|
|
|
|
if(!m_personalSettingsOnly)
|
|
{
|
|
if(!PARAM_ignoreprofile.Get())
|
|
{
|
|
// build custom setting array
|
|
XUSER_PROFILE_SETTING& specificSettings = g_ProfileSettingResults->pSettings[XPROFILE_TITLE_SPECIFIC1_INDEX];
|
|
Assert(specificSettings.dwSettingId == XPROFILE_TITLE_SPECIFIC1);
|
|
int num = specificSettings.data.binary.cbData / sizeof(CustomSetting);
|
|
|
|
m_settings.ResetCount();
|
|
if(num)
|
|
{
|
|
CustomSetting* pSetting = (CustomSetting*)specificSettings.data.binary.pbData;
|
|
while(num--)
|
|
{
|
|
#if !__FINAL
|
|
if(pSetting->id != ignoreProfileSetting)
|
|
#endif
|
|
{
|
|
m_settings.PushAndGrow(*pSetting++);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if settings don't exist then use the xbox settings
|
|
if(!Exists(TARGETING_MODE))
|
|
Set(TARGETING_MODE, (g_ProfileSettingResults->pSettings[XPROFILE_GAMER_ACTION_AUTO_AIM_INDEX].data.nData > 0) ? (int)CPedTargetEvaluator::TARGETING_OPTION_GTA_TRADITIONAL : (int)CPedTargetEvaluator::TARGETING_OPTION_FREEAIM );
|
|
|
|
if(!Exists(AXIS_INVERSION))
|
|
Set(AXIS_INVERSION, g_ProfileSettingResults->pSettings[XPROFILE_GAMER_YAXIS_INVERSION_INDEX].data.nData);
|
|
if(!Exists(CONTROLLER_VIBRATION))
|
|
Set(CONTROLLER_VIBRATION, g_ProfileSettingResults->pSettings[XPROFILE_OPTION_CONTROLLER_VIBRATION_INDEX].data.nData);
|
|
if(!Exists(CONTROLLER_SENSITIVITY))
|
|
{
|
|
switch(g_ProfileSettingResults->pSettings[XPROFILE_GAMER_CONTROL_SENSITIVITY_INDEX].data.nData)
|
|
{
|
|
case XPROFILE_CONTROL_SENSITIVITY_MEDIUM:
|
|
Set(CONTROLLER_SENSITIVITY, 1);
|
|
break;
|
|
case XPROFILE_CONTROL_SENSITIVITY_LOW:
|
|
Set(CONTROLLER_SENSITIVITY, 0);
|
|
break;
|
|
case XPROFILE_CONTROL_SENSITIVITY_HIGH:
|
|
Set(CONTROLLER_SENSITIVITY, 2);
|
|
break;
|
|
default:
|
|
Assertf(0, "Unrecognised controller sensitivity value");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// always set these parameter as we can't override them in game
|
|
Set(VOICE_THRU_SPEAKERS, g_ProfileSettingResults->pSettings[XPROFILE_OPTION_VOICE_THRU_SPEAKERS_INDEX].data.nData);
|
|
Set(VOICE_MUTED, g_ProfileSettingResults->pSettings[XPROFILE_OPTION_VOICE_MUTED_INDEX].data.nData);
|
|
Set(VOICE_VOLUME, g_ProfileSettingResults->pSettings[XPROFILE_OPTION_VOICE_VOLUME_INDEX].data.nData);
|
|
|
|
Set(GAMERCARD_REGION, g_ProfileSettingResults->pSettings[XPROFILE_GAMERCARD_REGION_INDEX].data.nData);
|
|
}
|
|
#elif USE_PROFILE_SAVEGAME
|
|
if (bWait)
|
|
{
|
|
PF_PUSH_TIMEBAR("CGenericGameStorage Update");
|
|
while (m_ProfileLoadStructure.GetStatus() == MEM_CARD_BUSY)
|
|
{
|
|
CGenericGameStorage::Update();
|
|
sysIpcSleep(1);
|
|
}
|
|
PF_POP_TIMEBAR();
|
|
}
|
|
else
|
|
{
|
|
if (m_ProfileLoadStructure.GetStatus() == MEM_CARD_BUSY)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(!PARAM_ignoreprofile.Get())
|
|
{
|
|
if( (m_ProfileLoadStructure.GetSizeOfLoadedProfile() > 0) &&
|
|
m_ProfileLoadStructure.GetSizeOfLoadedProfile() <= (u32)GetSizeOfPSProfileFile() &&
|
|
g_ProfileSettingBuffer.m_version == SETTINGS_VERSION)
|
|
{
|
|
// check crc, return if it isnt correct
|
|
if(g_ProfileSettingBuffer.m_crc != g_ProfileSettingBuffer.CalculateCrc())
|
|
{
|
|
m_valid = false;
|
|
return true;
|
|
}
|
|
|
|
m_settings.ResetCount();
|
|
for(s32 i=0; i<g_ProfileSettingBuffer.m_num; i++)
|
|
{
|
|
#if !__FINAL
|
|
if(g_ProfileSettingBuffer.m_settings[i].id != ignoreProfileSetting)
|
|
#endif
|
|
{
|
|
m_settings.PushAndGrow(g_ProfileSettingBuffer.m_settings[i]);
|
|
}
|
|
}
|
|
|
|
gnetDebug1("Read() - Finished.");
|
|
|
|
#if !__FINAL
|
|
if(PARAM_spewheistvalues.Get())
|
|
{
|
|
gnetDebug1("Value for FREEMODE_PROLOGUE_COMPLETE_CHAR0 with id='%d'.", this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR0));
|
|
gnetDebug1("Value for FREEMODE_PROLOGUE_COMPLETE_CHAR1 with id='%d'.", this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR1));
|
|
gnetDebug1("Value for FREEMODE_PROLOGUE_COMPLETE_CHAR2 with id='%d'.", this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR2));
|
|
gnetDebug1("Value for FREEMODE_PROLOGUE_COMPLETE_CHAR3 with id='%d'.", this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR3));
|
|
gnetDebug1("Value for FREEMODE_PROLOGUE_COMPLETE_CHAR4 with id='%d'.", this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR4));
|
|
}
|
|
#endif // !__FINAL
|
|
}
|
|
}
|
|
|
|
m_valid = true;
|
|
|
|
#elif RSG_PC
|
|
m_valid = true;
|
|
#endif
|
|
|
|
// Activate display calibration at startup is profile setting doesnt exist
|
|
if(Exists(DISPLAY_GAMMA))
|
|
CDisplayCalibration::ActivateAtStartup(false);
|
|
|
|
|
|
sysLanguage language = g_SysService.GetSystemLanguage();
|
|
|
|
// Possible language override
|
|
const char* langString;
|
|
if(PARAM_uilanguage.Get(langString))
|
|
{
|
|
language = (sysLanguage) TheText.GetLanguageFromName(langString);
|
|
Clear(DISPLAY_LANGUAGE);
|
|
}
|
|
|
|
if(language != LANGUAGE_UNDEFINED)
|
|
{
|
|
if (Exists(DISPLAY_LANGUAGE))
|
|
{
|
|
Set(CProfileSettings::NEW_DISPLAY_LANGUAGE, GetInt(DISPLAY_LANGUAGE));
|
|
}
|
|
else
|
|
{
|
|
Set(CProfileSettings::NEW_DISPLAY_LANGUAGE, (int) language);
|
|
}
|
|
}
|
|
|
|
if(m_readCallback)
|
|
m_readCallback();
|
|
|
|
m_hasChanged = false;
|
|
m_personalSettingsOnly = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#if RSG_PC
|
|
static sysIpcThreadId s_SavePcProfileThreadId = sysIpcThreadIdInvalid;
|
|
|
|
static bool s_bSavePcProfileThreadHasBeenStarted = false;
|
|
static volatile bool s_bSavePcProfileThreadIsFinished = false;
|
|
static volatile bool s_bSavePcProfileThreadFailed = false;
|
|
|
|
// DECLARE_THREAD_FUNC
|
|
void s_SavePcProfileThreadFunc(void*)
|
|
{
|
|
PF_PUSH_MARKER("SavePcProfile");
|
|
s_bSavePcProfileThreadFailed = false;
|
|
|
|
char fullPath[rgsc::RGSC_MAX_PATH] = {0};
|
|
|
|
if(g_rlPc.IsInitialized() && g_rlPc.GetProfileManager()->IsSignedIn())
|
|
{
|
|
if(AssertVerify(SUCCEEDED(g_rlPc.GetFileSystem()->GetTitleProfileDirectory(fullPath, true))))
|
|
{
|
|
safecat(fullPath, PC_SETTINGS_FILENAME);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
safecpy(fullPath, PC_SETTINGS_PATH); // using this as a default for -nosocialclub
|
|
}
|
|
|
|
ASSET.CreateLeadingPath(fullPath);
|
|
fiStream* pStream = ASSET.Create(fullPath, "");
|
|
if (Verifyf(pStream, "Couldn't open pc_settings.bin to write."))
|
|
{
|
|
pStream->Write(s_PcSettingsToSave, sizeof(CProfileSettings::CustomSetting) * s_NumberOfPcSettingsToSave);
|
|
pStream->Close();
|
|
}
|
|
else
|
|
{
|
|
s_bSavePcProfileThreadFailed = true;
|
|
}
|
|
|
|
#if !__FINAL
|
|
unsigned current, maxi;
|
|
if (sysIpcEstimateStackUsage(current,maxi))
|
|
Displayf("Save PC Profile thread used %u of %u bytes stack space.",current,maxi);
|
|
#endif
|
|
|
|
PF_POP_MARKER();
|
|
|
|
s_bSavePcProfileThreadIsFinished = true;
|
|
}
|
|
|
|
bool CProfileSettings::StartSavePcProfileThread()
|
|
{
|
|
if (s_SavePcProfileThreadId != sysIpcThreadIdInvalid)
|
|
{
|
|
Errorf("CProfileSettings::StartSavePcProfileThread started twice. Previous thread not finished, can't start.");
|
|
return false;
|
|
}
|
|
|
|
if (s_bSavePcProfileThreadHasBeenStarted)
|
|
{
|
|
Errorf("CProfileSettings::StartSavePcProfileThread - s_bSavePcProfileThreadHasBeenStarted is true. Is there already a save in progress?");
|
|
return false;
|
|
}
|
|
|
|
s_bSavePcProfileThreadIsFinished = false;
|
|
s_bSavePcProfileThreadFailed = false;
|
|
|
|
s_SavePcProfileThreadId = sysIpcCreateThread(s_SavePcProfileThreadFunc, NULL, 16384, PRIO_BELOW_NORMAL, "SavePcProfileThread", 0, "SavePcProfileThread");
|
|
|
|
if (s_SavePcProfileThreadId != sysIpcThreadIdInvalid)
|
|
{
|
|
s_bSavePcProfileThreadHasBeenStarted = true;
|
|
}
|
|
else
|
|
{
|
|
s_bSavePcProfileThreadHasBeenStarted = false;
|
|
}
|
|
|
|
return s_bSavePcProfileThreadHasBeenStarted;
|
|
}
|
|
|
|
void CProfileSettings::EndSavePcProfileThread()
|
|
{
|
|
if (s_SavePcProfileThreadId != sysIpcThreadIdInvalid)
|
|
{
|
|
sysIpcWaitThreadExit(s_SavePcProfileThreadId);
|
|
s_SavePcProfileThreadId = sysIpcThreadIdInvalid;
|
|
}
|
|
|
|
s_bSavePcProfileThreadHasBeenStarted = false;
|
|
}
|
|
|
|
// Return false if a save is in progress
|
|
// Return true if a save has just finished, or if no save is currently running
|
|
bool CProfileSettings::CheckSavePcProfileThread()
|
|
{
|
|
if (s_bSavePcProfileThreadHasBeenStarted)
|
|
{
|
|
if (s_bSavePcProfileThreadIsFinished)
|
|
{
|
|
EndSavePcProfileThread();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endif // RSG_PC
|
|
|
|
|
|
bool CProfileSettings::StartWrite(bool DOWNLOAD0_PROFILE_ONLY(ignoreStreamingState))
|
|
{
|
|
#if __XENON
|
|
Assertf(m_valid, "Cannot write invalid profile settings");
|
|
// if there are any custom settings. Store them in title specific slot in profile settings
|
|
XUSER_PROFILE_SETTING& specificSettings = g_ProfileSettingResults->pSettings[XPROFILE_TITLE_SPECIFIC1_INDEX];
|
|
Assert(specificSettings.dwSettingId == XPROFILE_TITLE_SPECIFIC1);
|
|
specificSettings.data.type = XUSER_DATA_TYPE_BINARY;
|
|
if(m_settings.GetCount() > 0)
|
|
{
|
|
specificSettings.data.binary.cbData = m_settings.GetCount() * sizeof(CustomSetting);
|
|
specificSettings.data.binary.pbData = (BYTE*)m_settings.GetElements();
|
|
// Data size can't be greater than 1K
|
|
Assert(specificSettings.data.binary.cbData <= 1024);
|
|
}
|
|
|
|
ASSERT_ONLY(DWORD status = )XUserWriteProfileSettings(m_localIndex,
|
|
1,
|
|
&g_ProfileSettingResults->pSettings[XPROFILE_TITLE_SPECIFIC1_INDEX],
|
|
&g_overlapped);
|
|
Assert(status == ERROR_IO_PENDING);
|
|
return true;
|
|
|
|
#elif USE_PROFILE_SAVEGAME
|
|
|
|
// create buffer
|
|
if (!Verifyf( m_settings.GetCount() <= TOTAL_NUM_SETTINGS, "CProfileSettings::StartWrite - Too many settings, %d of %d requested for serialization", m_settings.GetCount(), TOTAL_NUM_SETTINGS ))
|
|
{
|
|
for (int i = TOTAL_NUM_SETTINGS; i < m_settings.GetCount(); ++i)
|
|
{
|
|
gnetDebug1("Will ignore setting id: %d", m_settings[i].id);
|
|
}
|
|
}
|
|
|
|
int count = ::Min(m_settings.GetCount(), TOTAL_NUM_SETTINGS);
|
|
g_ProfileSettingBuffer.m_num = count;//m_settings.GetCount();
|
|
g_ProfileSettingBuffer.m_version = SETTINGS_VERSION;
|
|
sysMemCpy(g_ProfileSettingBuffer.m_settings, m_settings.GetElements(), count * sizeof(CustomSetting));
|
|
// calculate crc before continuing
|
|
g_ProfileSettingBuffer.m_crc = g_ProfileSettingBuffer.CalculateCrc();
|
|
|
|
#if USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
m_ProfileSaveStructure.Init(m_localIndex, &g_ProfileSettingBuffer, GetSizeOfPSProfileFile(), ignoreStreamingState? CSavegameQueuedOperation_ProfileSave::SAVE_BOTH_PROFILES : CSavegameQueuedOperation_ProfileSave::SAVE_BACKUP_PROFILE_ONLY);
|
|
#else
|
|
m_ProfileSaveStructure.Init(m_localIndex, g_profileName, GetFilenameOfPSProfile(), &g_ProfileSettingBuffer, GetSizeOfPSProfileFile());
|
|
#endif
|
|
|
|
if (!CGenericGameStorage::PushOnToSavegameQueue(&m_ProfileSaveStructure))
|
|
{
|
|
Warningf("CProfileSettings::StartWrite - CGenericGameStorage::PushOnToSavegameQueue failed\n");
|
|
return false;
|
|
}
|
|
|
|
gnetDebug1("StartWrite() - Writting");
|
|
|
|
return true;
|
|
|
|
#elif RSG_PC
|
|
// Take a snapshot of the current profile settings. The save will take a number of frames to complete.
|
|
if (!Verifyf( m_settings.GetCount() <= TOTAL_NUM_PC_SETTINGS, "CProfileSettings::StartWrite - Too many settings, %d of %d requested for serialization", m_settings.GetCount(), TOTAL_NUM_PC_SETTINGS ))
|
|
{
|
|
for (int i = TOTAL_NUM_PC_SETTINGS; i < m_settings.GetCount(); ++i)
|
|
{
|
|
gnetDebug1("Will ignore setting id: %d", i, m_settings[i].id);
|
|
}
|
|
}
|
|
s_NumberOfPcSettingsToSave = ::Min(m_settings.GetCount(), TOTAL_NUM_PC_SETTINGS);
|
|
|
|
sysMemCpy(s_PcSettingsToSave, m_settings.GetElements(), s_NumberOfPcSettingsToSave * sizeof(CustomSetting));
|
|
|
|
if (StartSavePcProfileThread())
|
|
{
|
|
return true; // successfully started thread
|
|
}
|
|
else
|
|
{
|
|
return false; // failed to start thread
|
|
}
|
|
#elif RSG_DURANGO
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool CProfileSettings::FinishWrite(bool
|
|
#if __XENON || USE_PROFILE_SAVEGAME || RSG_PC
|
|
bWait
|
|
#endif
|
|
)
|
|
{
|
|
#if __XENON
|
|
DWORD status;
|
|
DWORD result;
|
|
|
|
status = XGetOverlappedResult(&g_overlapped, &result, bWait);
|
|
if(status == ERROR_IO_INCOMPLETE)
|
|
return false;
|
|
|
|
if(status == ERROR_SUCCESS)
|
|
m_timeOfLastWrite = fwTimer::GetSystemTimeInMilliseconds();
|
|
|
|
#elif USE_PROFILE_SAVEGAME
|
|
if (bWait)
|
|
{
|
|
PF_PUSH_TIMEBAR("CGenericGameStorage Update");
|
|
while (m_ProfileSaveStructure.GetStatus() == MEM_CARD_BUSY)
|
|
{
|
|
CGenericGameStorage::Update();
|
|
sysIpcSleep(1);
|
|
}
|
|
PF_POP_TIMEBAR();
|
|
}
|
|
else
|
|
{
|
|
if (m_ProfileSaveStructure.GetStatus() == MEM_CARD_BUSY)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
#elif RSG_PC
|
|
if (bWait)
|
|
{
|
|
PF_PUSH_TIMEBAR("CProfileSettings::FinishWrite");
|
|
while (CheckSavePcProfileThread() == false)
|
|
{
|
|
sysIpcSleep(1);
|
|
}
|
|
PF_POP_TIMEBAR();
|
|
}
|
|
else
|
|
{
|
|
if (CheckSavePcProfileThread() == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
gnetDebug1("FinishWrite() - done.");
|
|
|
|
return true;
|
|
}
|
|
|
|
#if USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
void CProfileSettings::UpdateMainProfileSave()
|
|
{
|
|
if (m_bMainProfileSaveIsRequired)
|
|
{
|
|
if (!CNetwork::IsNetworkOpen() && !CNetwork::HasCalledFirstEntryOpen()) // Don't save the profile to the savegame folder during multiplayer
|
|
{
|
|
if (CGenericGameStorage::IsSafeToUseSaveLibrary())
|
|
{
|
|
if (m_MainProfileSaveStructure.GetStatus() != MEM_CARD_BUSY)
|
|
{
|
|
if (CSavegameQueue::IsEmpty())
|
|
{ // To give the main profile save the best chance of completing quickly, only push it on to the queue if the queue is empty.
|
|
// Any delay in starting this save increases the likelihood of the game getting back into a state where IsSafeToUseSaveLibrary() would have returned false.
|
|
m_MainProfileSaveStructure.Init(m_localIndex, &g_ProfileSettingBuffer, GetSizeOfPSProfileFile(), CSavegameQueuedOperation_ProfileSave::SAVE_MAIN_PROFILE_ONLY);
|
|
if (Verifyf(CGenericGameStorage::PushOnToSavegameQueue(&m_MainProfileSaveStructure), "CProfileSettings::UpdateMainProfileSave - failed to push a main profile save on to the savegame queue"))
|
|
{
|
|
m_bMainProfileSaveIsRequired = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif // USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
|
|
void CProfileSettings::UpdateProfileSettings(bool bWait, bool ORBIS_ONLY(ignoreStreamingState))
|
|
{
|
|
PF_AUTO_PUSH_TIMEBAR("CProfileSettings UpdateProfileSettings");
|
|
|
|
#if __WIN32PC && (!__FINAL || defined(MASTER_NO_SCUI))
|
|
if((g_rlPc.IsInitialized() == false))
|
|
{
|
|
// for cases where -nosocialclub is used, we won't have a profile signed in
|
|
if (!m_valid)
|
|
{
|
|
Read();
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// Check if we have a main gamer setup
|
|
const rlGamerInfo* pGamerInfo = NetworkInterface::GetActiveGamerInfo();
|
|
if(pGamerInfo)
|
|
{
|
|
// If gamer id has changed then read profile settings
|
|
if(pGamerInfo->GetGamerId() != m_gamerId)
|
|
{
|
|
m_gamerId = pGamerInfo->GetGamerId();
|
|
m_localIndex = pGamerInfo->GetLocalIndex();
|
|
Read();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_localIndex = -1;
|
|
m_gamerId.Clear();
|
|
m_readPending = false;
|
|
m_writePending = false;
|
|
// Revert to default profile settings if a profile has been loaded
|
|
if(m_valid)
|
|
{
|
|
Default();
|
|
m_valid = false;
|
|
}
|
|
}
|
|
|
|
// If gamer id is invalid then disable any pending read/writes
|
|
if(!m_gamerId.IsValid())
|
|
{
|
|
m_readPending = false;
|
|
m_writePending = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
#if USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
UpdateMainProfileSave();
|
|
#endif // USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
|
|
#if DEBUG_DRAW && __BANK && __XENON
|
|
if (sm_bDisplayDebugText)
|
|
{
|
|
s32 timeTillNextProfileWrite = 0;
|
|
if (m_timeOfLastWrite > 0)
|
|
{
|
|
timeTillNextProfileWrite = (m_timeOfLastWrite + sm_MinimumTimeBetweenProfileSaves) - fwTimer::GetSystemTimeInMilliseconds();
|
|
if (timeTillNextProfileWrite < 0)
|
|
{
|
|
timeTillNextProfileWrite = 0;
|
|
}
|
|
}
|
|
grcDebugDraw::AddDebugOutput("timeTillNextProfileWrite = %d %s", timeTillNextProfileWrite, m_writePending?"Write Pending":"");
|
|
}
|
|
#endif // DEBUG_DRAW && __BANK && __XENON
|
|
|
|
if(m_reading)
|
|
{
|
|
if(FinishRead(bWait))
|
|
m_reading = false;
|
|
}
|
|
else if(m_writing)
|
|
{
|
|
if(FinishWrite(bWait))
|
|
{
|
|
m_writing = false;
|
|
}
|
|
}
|
|
else if(m_readPending)
|
|
{
|
|
#if RSG_DURANGO
|
|
if(CLiveManager::SignedInIntoNewProfileAfterSuspendMode())
|
|
{
|
|
gnetDebug1("UpdateProfileSettings - The session is just about to restart because the player has signed out of one profile and into a different profile. Delay the profile settings read until the beginning of the new session");
|
|
}
|
|
else
|
|
#endif // RSG_DURANGO
|
|
{
|
|
if (CSystem::IsThisThreadId(SYS_THREAD_UPDATE))
|
|
{
|
|
if(StartRead())
|
|
m_reading = true;
|
|
m_readPending = false;
|
|
}
|
|
else
|
|
{
|
|
gnetDebug1("UpdateProfileSettings - we should only call StartRead() on the Update thread");
|
|
}
|
|
}
|
|
}
|
|
// Can only write profile once every 5 minutes. If time of last write is zero then profile settings have never been set
|
|
else if(m_writePending
|
|
&& (fwTimer::GetSystemTimeInMilliseconds() > m_timeOfLastWrite + sm_MinimumTimeBetweenProfileSaves || m_timeOfLastWrite == 0)
|
|
#if USE_PROFILE_SAVEGAME
|
|
#if RSG_ORBIS
|
|
&& (CSavegameNewGameChecks::HaveFreeSpaceChecksCompleted())
|
|
#if !USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
&& (CGenericGameStorage::IsSafeToUseSaveLibrary() || ignoreStreamingState)
|
|
#endif // !USE_DOWNLOAD0_FOR_PROFILE_BACKUP
|
|
#endif // RSG_ORBIS
|
|
&& (!m_bDontWriteProfile)
|
|
#endif // USE_PROFILE_SAVEGAME
|
|
)
|
|
{
|
|
#if RSG_ORBIS
|
|
if(StartWrite(ignoreStreamingState))
|
|
#else
|
|
if(StartWrite())
|
|
#endif
|
|
{
|
|
m_writing = true;
|
|
}
|
|
m_writePending = false;
|
|
}
|
|
|
|
// If update has been passed that it has to wait then finish anything we started
|
|
if(bWait)
|
|
{
|
|
if(m_reading)
|
|
{
|
|
if(FinishRead(bWait))
|
|
m_reading = false;
|
|
}
|
|
else if(m_writing)
|
|
{
|
|
if(FinishWrite(bWait))
|
|
{
|
|
m_writing = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// name: CProfileSettings::OnPresenceEvent
|
|
// description: This is called whenever there is a user presence event. We are only interested in the profile change event
|
|
#if __XENON || RSG_DURANGO
|
|
void CProfileSettings::OnPresenceEvent(const rlPresenceEvent* evt)
|
|
#else
|
|
void CProfileSettings::OnPresenceEvent(const rlPresenceEvent* )
|
|
#endif
|
|
{
|
|
#if __XENON || RSG_DURANGO
|
|
if(PRESENCE_EVENT_PROFILE_CHANGED == evt->GetId())
|
|
{
|
|
// If we receive a profile change event then read profile settings again
|
|
if(NetworkInterface::GetActiveGamerInfo() &&
|
|
NetworkInterface::GetActiveGamerInfo()->GetGamerId() == evt->m_ProfileChanged->m_GamerInfo.GetGamerId())
|
|
{
|
|
Displayf("PRESENCE_EVENT_PROFILE_CHANGED - GamerId = %lu - about to call Read", evt->m_ProfileChanged->m_GamerInfo.GetGamerId().GetId());
|
|
CProfileSettings::GetInstance().Read(true);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CProfileSettings::Default()
|
|
{
|
|
m_settings.ResetCount();
|
|
|
|
if(m_readCallback)
|
|
m_readCallback();
|
|
}
|
|
|
|
//
|
|
// name: CProfileSettings::Exists
|
|
// description: Returns if a profile setting exists
|
|
bool CProfileSettings::Exists(ProfileSettingId id)
|
|
{
|
|
return (FindSetting(id) != -1);
|
|
}
|
|
|
|
//
|
|
// name: CProfileSettings::Clear
|
|
// description: Remove a setting
|
|
void CProfileSettings::Clear(ProfileSettingId id)
|
|
{
|
|
s32 index = FindSetting(id);
|
|
if(index != -1)
|
|
{
|
|
m_hasChanged = true;
|
|
m_settings.DeleteFast(index);
|
|
}
|
|
}
|
|
|
|
bool CProfileSettings::IsReading() const
|
|
{
|
|
return m_reading || m_readPending;
|
|
}
|
|
|
|
bool CProfileSettings::IsWriting() const
|
|
{
|
|
return m_writing || m_writePending;
|
|
}
|
|
|
|
//
|
|
// name: CProfileSettings::FindSetting
|
|
// description: Find a setting in the list
|
|
s32 CProfileSettings::FindSetting(ProfileSettingId id)
|
|
{
|
|
for(s32 i=0; i<m_settings.GetCount(); i++)
|
|
{
|
|
if(m_settings[i].id == id)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// name: CProfileSettings::FindSettingPtr
|
|
// description: Find a setting in the list
|
|
CProfileSettings::CustomSetting* CProfileSettings::FindSettingPtr(ProfileSettingId id)
|
|
{
|
|
s32 index = FindSetting(id);
|
|
if(index != -1)
|
|
return &m_settings[index];
|
|
return NULL;
|
|
}
|
|
//
|
|
// name: CProfileSettings::SetCustom
|
|
// description: Get/Set for custom settings.
|
|
void CProfileSettings::Set(ProfileSettingId id, int value)
|
|
{
|
|
// if setting exists and it is the same then return. Doesn't set the hasChanged flag
|
|
if(Exists(id) && GetInt(id) == value)
|
|
return;
|
|
m_hasChanged = true;
|
|
|
|
#if !__FINAL
|
|
if(PARAM_spewheistvalues.Get())
|
|
{
|
|
if (FREEMODE_PROLOGUE_COMPLETE_CHAR0 == id)
|
|
{
|
|
gnetDebug1("%s:Set() for FREEMODE_PROLOGUE_COMPLETE_CHAR0 with old='%d', new='%d'.", CTheScripts::GetCurrentScriptNameAndProgramCounter(), this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR0), value);
|
|
rage::sysStack::PrintStackTrace();
|
|
}
|
|
else if (FREEMODE_PROLOGUE_COMPLETE_CHAR1 == id)
|
|
{
|
|
gnetDebug1("%s:Set() for FREEMODE_PROLOGUE_COMPLETE_CHAR1 with old='%d', new='%d'.", CTheScripts::GetCurrentScriptNameAndProgramCounter(), this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR1), value);
|
|
rage::sysStack::PrintStackTrace();
|
|
}
|
|
else if (FREEMODE_PROLOGUE_COMPLETE_CHAR2 == id)
|
|
{
|
|
gnetDebug1("%s:Set() for FREEMODE_PROLOGUE_COMPLETE_CHAR2 with old='%d', new='%d'.", CTheScripts::GetCurrentScriptNameAndProgramCounter(), this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR2), value);
|
|
rage::sysStack::PrintStackTrace();
|
|
}
|
|
else if (FREEMODE_PROLOGUE_COMPLETE_CHAR3 == id)
|
|
{
|
|
gnetDebug1("%s:Set() for FREEMODE_PROLOGUE_COMPLETE_CHAR3 with old='%d', new='%d'.", CTheScripts::GetCurrentScriptNameAndProgramCounter(), this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR3), value);
|
|
rage::sysStack::PrintStackTrace();
|
|
}
|
|
else if (FREEMODE_PROLOGUE_COMPLETE_CHAR4 == id)
|
|
{
|
|
gnetDebug1("%s:Set() for FREEMODE_PROLOGUE_COMPLETE_CHAR4 with old='%d', new='%d'.", CTheScripts::GetCurrentScriptNameAndProgramCounter(), this->GetInt(FREEMODE_PROLOGUE_COMPLETE_CHAR4), value);
|
|
rage::sysStack::PrintStackTrace();
|
|
}
|
|
}
|
|
#endif // !__FINAL
|
|
|
|
StatsInterface::UpdateProfileSetting(id);
|
|
|
|
CustomSetting* pSetting = FindSettingPtr(id);
|
|
if(pSetting)
|
|
pSetting->ivalue = value;
|
|
else
|
|
{
|
|
CustomSetting setting;
|
|
setting.id = id;
|
|
setting.ivalue = value;
|
|
m_settings.PushAndGrow(setting);
|
|
}
|
|
}
|
|
void CProfileSettings::Set(ProfileSettingId id, float value)
|
|
{
|
|
// if setting exists and it is the same then return. Doesn't set the hasChanged flag
|
|
if(Exists(id) && GetFloat(id) == value)
|
|
return;
|
|
m_hasChanged = true;
|
|
|
|
CustomSetting* pSetting = FindSettingPtr(id);
|
|
if(pSetting)
|
|
pSetting->fvalue = value;
|
|
else
|
|
{
|
|
CustomSetting setting;
|
|
setting.id = id;
|
|
setting.fvalue = value;
|
|
m_settings.PushAndGrow(setting);
|
|
}
|
|
}
|
|
int CProfileSettings::GetInt(ProfileSettingId id)
|
|
{
|
|
CustomSetting* pSetting = FindSettingPtr(id);
|
|
if(pSetting)
|
|
return pSetting->ivalue;
|
|
return 0;
|
|
}
|
|
float CProfileSettings::GetFloat(ProfileSettingId id)
|
|
{
|
|
CustomSetting* pSetting = FindSettingPtr(id);
|
|
if(pSetting)
|
|
return pSetting->fvalue;
|
|
return 0.0f;
|
|
}
|
|
|
|
|
|
#if USE_PROFILE_SAVEGAME
|
|
char *CProfileSettings::GetFilenameOfPSProfile()
|
|
{
|
|
return &g_fileName[0];
|
|
}
|
|
|
|
char16 *CProfileSettings::GetDisplayNameOfPSProfile()
|
|
{
|
|
return &g_profileName[0];
|
|
}
|
|
|
|
int CProfileSettings::GetSizeOfPSProfileFile()
|
|
{
|
|
return sizeof(g_ProfileSettingBuffer);
|
|
}
|
|
#endif
|
|
|
|
|
|
bool CProfileSettings::GetCountry(char (&countryCode)[3])
|
|
{
|
|
// Make sure the result is null terminated
|
|
countryCode[2] = '\0';
|
|
|
|
#if __PS3
|
|
SceNpCountryCode nPCountryCode;
|
|
int lang=0;
|
|
int err = sceNpManagerGetAccountRegion(&nPCountryCode, &lang);
|
|
if(err == 0) // Ok
|
|
{
|
|
countryCode[0] = nPCountryCode.data[0];
|
|
countryCode[1] = nPCountryCode.data[1];
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
uiErrorf("CProfileSettings::GetCountry - sceNpManagerGetAccountRegion returned an error 0x%x", err);
|
|
}
|
|
#elif __XENON
|
|
//For the 360, country comes from a profile setting
|
|
CompileTimeAssert(XONLINE_COUNTRY_UNKNOWN == 0);
|
|
CompileTimeAssert(XONLINE_COUNTRY_MAX <= 255);
|
|
const int regionCode = GetInt(GAMERCARD_REGION);
|
|
if (regionCode != 0 &&
|
|
Verifyf(regionCode <= 255, "XONLINE_COUNTRY is larger than expected (%d)", regionCode))
|
|
{
|
|
struct LiveCountryMapping
|
|
{
|
|
u8 m_LiveCountryCode;
|
|
char m_IsoCountryCode[2];
|
|
};
|
|
|
|
static const LiveCountryMapping liveCountryMappings[] = {
|
|
#include "LiveCountryMappings.h"
|
|
};
|
|
|
|
for (unsigned k = 0; k < COUNTOF(liveCountryMappings); k++)
|
|
{
|
|
if (liveCountryMappings[k].m_LiveCountryCode == (u8)regionCode)
|
|
{
|
|
countryCode[0] = liveCountryMappings[k].m_IsoCountryCode[0];
|
|
countryCode[1] = liveCountryMappings[k].m_IsoCountryCode[1];
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//Emit an error if we didn't find a mapping
|
|
uiErrorf("CProfileSettings::GetCountry - No XONLINE_COUNTRY mapping found for %d", regionCode);
|
|
}
|
|
else
|
|
{
|
|
uiErrorf("CProfileSettings::GetCountry - Failed to retrieve region from profile");
|
|
}
|
|
#elif RSG_ORBIS
|
|
if(RL_VERIFY_LOCAL_GAMER_INDEX(m_localIndex))
|
|
{
|
|
return g_rlNp.GetCountryCode(m_localIndex, countryCode);
|
|
}
|
|
#elif RSG_DURANGO
|
|
if(g_SysService.GetSystemCountry(countryCode))
|
|
{
|
|
return true;
|
|
}
|
|
#elif RSG_PC
|
|
// This shouldn't be called on PC. The SCUI (Social Club UI) requires the user to choose their country from a list.
|
|
Assert(false);
|
|
#else
|
|
Assert(false);
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
int CProfileSettings::GetReplayTutorialFlags()
|
|
{
|
|
int result = 0;
|
|
|
|
if( Exists( ROCKSTAR_EDITOR_TUTORIAL_FLAGS ) )
|
|
{
|
|
result = GetInt( ROCKSTAR_EDITOR_TUTORIAL_FLAGS );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void CProfileSettings::UpdateReplayTutorialFlags( s32 const tutorialFlag )
|
|
{
|
|
int const c_existingFlags = GetReplayTutorialFlags();
|
|
int const c_resultingFlags = c_existingFlags | tutorialFlag;
|
|
Set( ROCKSTAR_EDITOR_TUTORIAL_FLAGS, c_resultingFlags );
|
|
}
|