You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
7.8 KiB
296 lines
7.8 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose: Xbox Launch Routines.
|
||
|
//
|
||
|
//=====================================================================================//
|
||
|
|
||
|
#ifndef _XBOX_LAUNCH_H_
|
||
|
#define _XBOX_LAUNCH_H_
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#ifndef _CERT
|
||
|
#pragma comment( lib, "xbdm.lib" )
|
||
|
#endif
|
||
|
|
||
|
// id and version are used to tag the data blob, currently only need a singe hardcoded id
|
||
|
// when the version and id don't match, the data blob is not ours
|
||
|
#define VALVE_LAUNCH_ID (('V'<<24)|('A'<<16)|('L'<<8)|('V'<<0))
|
||
|
#define VALVE_LAUNCH_VERSION 1
|
||
|
|
||
|
// launch flags
|
||
|
#define LF_ISDEBUGGING 0x80000000 // set if session was active prior to launch
|
||
|
#define LF_INTERNALLAUNCH 0x00000001 // set if launch was internal (as opposed to dashboard)
|
||
|
#define LF_EXITFROMINSTALLER 0x00000002 // set if exit was from an installer
|
||
|
#define LF_EXITFROMGAME 0x00000004 // set if exit was from a game
|
||
|
#define LF_EXITFROMCHOOSER 0x00000008 // set if exit was from the chooser
|
||
|
#define LF_GAMERESTART 0x00000010 // set if game wants to restart self (skips appchooser)
|
||
|
#define LF_INVITERESTART 0x00000020 // set if game was invited from another app (launches TF and fires off session connect)
|
||
|
|
||
|
#pragma pack(1)
|
||
|
struct launchHeader_t
|
||
|
{
|
||
|
unsigned int id;
|
||
|
unsigned int version;
|
||
|
unsigned int flags;
|
||
|
|
||
|
int nStorageID;
|
||
|
int nUserID;
|
||
|
int bForceEnglish;
|
||
|
XNKID nInviteSessionID;
|
||
|
|
||
|
// for caller defined data, occurs after this header
|
||
|
// limited to slightly less than MAX_LAUNCH_DATA_SIZE
|
||
|
unsigned int nDataSize;
|
||
|
};
|
||
|
#pragma pack()
|
||
|
|
||
|
// per docs, no larger than MAX_LAUNCH_DATA_SIZE
|
||
|
union xboxLaunchData_t
|
||
|
{
|
||
|
launchHeader_t header;
|
||
|
char data[MAX_LAUNCH_DATA_SIZE];
|
||
|
};
|
||
|
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
// Simple class to wrap the peristsent launch payload.
|
||
|
//
|
||
|
// Can be used by an application that does not use tier0 (i.e. the launcher).
|
||
|
// Primarily designed to be anchored in tier0, so multiple systems can easily query and
|
||
|
// set the persistent payload.
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
class CXboxLaunch
|
||
|
{
|
||
|
public:
|
||
|
CXboxLaunch()
|
||
|
{
|
||
|
ResetLaunchData();
|
||
|
}
|
||
|
|
||
|
void ResetLaunchData()
|
||
|
{
|
||
|
// invalid until established
|
||
|
// nonzero identifies a valid payload
|
||
|
m_LaunchDataSize = 0;
|
||
|
|
||
|
m_Launch.header.id = 0;
|
||
|
m_Launch.header.version = 0;
|
||
|
m_Launch.header.flags = 0;
|
||
|
|
||
|
m_Launch.header.nStorageID = XBX_INVALID_STORAGE_ID;
|
||
|
m_Launch.header.nUserID = XBX_INVALID_USER_ID;
|
||
|
m_Launch.header.bForceEnglish = false;
|
||
|
|
||
|
memset( &m_Launch.header.nInviteSessionID, 0, sizeof( m_Launch.header.nInviteSessionID ) );
|
||
|
|
||
|
m_Launch.header.nDataSize = 0;
|
||
|
}
|
||
|
|
||
|
// Returns how much space can be used by caller
|
||
|
int MaxPayloadSize()
|
||
|
{
|
||
|
return sizeof( xboxLaunchData_t ) - sizeof( launchHeader_t );
|
||
|
}
|
||
|
|
||
|
bool SetLaunchData( void *pData, int dataSize, int flags = 0 )
|
||
|
{
|
||
|
if ( pData && dataSize && dataSize > MaxPayloadSize() )
|
||
|
{
|
||
|
// not enough room
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if ( pData && dataSize && dataSize <= MaxPayloadSize() )
|
||
|
{
|
||
|
memcpy( m_Launch.data + sizeof( launchHeader_t ), pData, dataSize );
|
||
|
m_Launch.header.nDataSize = dataSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_Launch.header.nDataSize = 0;
|
||
|
}
|
||
|
|
||
|
flags |= LF_INTERNALLAUNCH;
|
||
|
#if !defined( _CERT )
|
||
|
if ( DmIsDebuggerPresent() )
|
||
|
{
|
||
|
flags |= LF_ISDEBUGGING;
|
||
|
}
|
||
|
#endif
|
||
|
m_Launch.header.id = VALVE_LAUNCH_ID;
|
||
|
m_Launch.header.version = VALVE_LAUNCH_VERSION;
|
||
|
m_Launch.header.flags = flags;
|
||
|
|
||
|
XSetLaunchData( &m_Launch, MAX_LAUNCH_DATA_SIZE );
|
||
|
|
||
|
// assume successful, mark as valid
|
||
|
m_LaunchDataSize = MAX_LAUNCH_DATA_SIZE;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
// Returns TRUE if the launch data blob is available. FALSE otherwise.
|
||
|
// Caller is expected to validate and interpret contents based on ID.
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
bool GetLaunchData( unsigned int *pID, void **pData, int *pDataSize )
|
||
|
{
|
||
|
if ( !m_LaunchDataSize )
|
||
|
{
|
||
|
// purposely not doing this in the constructor (unstable as used by tier0), but on first fetch
|
||
|
bool bValid = false;
|
||
|
DWORD dwLaunchDataSize;
|
||
|
DWORD dwStatus = XGetLaunchDataSize( &dwLaunchDataSize );
|
||
|
if ( dwStatus == ERROR_SUCCESS && dwLaunchDataSize <= MAX_LAUNCH_DATA_SIZE )
|
||
|
{
|
||
|
dwStatus = XGetLaunchData( (void*)&m_Launch, dwLaunchDataSize );
|
||
|
if ( dwStatus == ERROR_SUCCESS )
|
||
|
{
|
||
|
bValid = true;
|
||
|
m_LaunchDataSize = dwLaunchDataSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( !bValid )
|
||
|
{
|
||
|
ResetLaunchData();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// a valid launch payload could be ours (re-launch) or from an alternate booter (demo launcher)
|
||
|
if ( m_LaunchDataSize == MAX_LAUNCH_DATA_SIZE && m_Launch.header.id == VALVE_LAUNCH_ID && m_Launch.header.version == VALVE_LAUNCH_VERSION )
|
||
|
{
|
||
|
// internal recognized format
|
||
|
if ( pID )
|
||
|
{
|
||
|
*pID = m_Launch.header.id;
|
||
|
}
|
||
|
if ( pData )
|
||
|
{
|
||
|
*pData = m_Launch.data + sizeof( launchHeader_t );
|
||
|
}
|
||
|
if ( pDataSize )
|
||
|
{
|
||
|
*pDataSize = m_Launch.header.nDataSize;
|
||
|
}
|
||
|
}
|
||
|
else if ( m_LaunchDataSize )
|
||
|
{
|
||
|
// not ours, unknown format, caller interprets
|
||
|
if ( pID )
|
||
|
{
|
||
|
// assume payload was packaged with an initial ID
|
||
|
*pID = *(unsigned int *)m_Launch.data;
|
||
|
}
|
||
|
if ( pData )
|
||
|
{
|
||
|
*pData = m_Launch.data;
|
||
|
}
|
||
|
if ( pDataSize )
|
||
|
{
|
||
|
*pDataSize = m_LaunchDataSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// valid when data is available (not necessarily valve's tag)
|
||
|
return m_LaunchDataSize != 0;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
// Returns TRUE if the launch data blob is available. FALSE otherwise.
|
||
|
// Data blob could be ours or not.
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
bool RestoreLaunchData()
|
||
|
{
|
||
|
return GetLaunchData( NULL, NULL, NULL );
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
// Restores the data blob. If the data blob is not ours, resets it.
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
void RestoreOrResetLaunchData()
|
||
|
{
|
||
|
RestoreLaunchData();
|
||
|
if ( m_Launch.header.id != VALVE_LAUNCH_ID || m_Launch.header.version != VALVE_LAUNCH_VERSION )
|
||
|
{
|
||
|
// not interested in somebody else's data
|
||
|
ResetLaunchData();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
// Returns OUR internal launch flags.
|
||
|
//--------------------------------------------------------------------------------------
|
||
|
int GetLaunchFlags()
|
||
|
{
|
||
|
// establish the data
|
||
|
RestoreOrResetLaunchData();
|
||
|
return m_Launch.header.flags;
|
||
|
}
|
||
|
|
||
|
int GetStorageID( void )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
return m_Launch.header.nStorageID;
|
||
|
}
|
||
|
void SetStorageID( int storageID )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
m_Launch.header.nStorageID = storageID;
|
||
|
}
|
||
|
|
||
|
int GetUserID( void )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
return m_Launch.header.nUserID;
|
||
|
}
|
||
|
void SetUserID( int userID )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
m_Launch.header.nUserID = userID;
|
||
|
}
|
||
|
|
||
|
bool GetForceEnglish( void )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
return m_Launch.header.bForceEnglish ? true : false;
|
||
|
}
|
||
|
void SetForceEnglish( bool bForceEnglish )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
m_Launch.header.bForceEnglish = bForceEnglish;
|
||
|
}
|
||
|
|
||
|
void GetInviteSessionID( XNKID *pSessionID )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
*pSessionID = m_Launch.header.nInviteSessionID;
|
||
|
}
|
||
|
void SetInviteSessionID( XNKID *pSessionID )
|
||
|
{
|
||
|
RestoreOrResetLaunchData();
|
||
|
m_Launch.header.nInviteSessionID = *pSessionID;
|
||
|
}
|
||
|
|
||
|
void Launch( const char *pNewImageName = NULL )
|
||
|
{
|
||
|
if ( !pNewImageName )
|
||
|
{
|
||
|
pNewImageName = "default.xex";
|
||
|
}
|
||
|
|
||
|
XLaunchNewImage( pNewImageName, 0 );
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
xboxLaunchData_t m_Launch;
|
||
|
DWORD m_LaunchDataSize;
|
||
|
};
|
||
|
|
||
|
#if defined( PLATFORM_H )
|
||
|
// For applications that use tier0.dll
|
||
|
PLATFORM_INTERFACE CXboxLaunch *XboxLaunch();
|
||
|
#endif
|
||
|
|
||
|
#endif
|