452 lines
11 KiB
C++
452 lines
11 KiB
C++
//========= Copyright © 1996-2005, 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_WARMRESTART 0x00000010 // set if game wants to restart self (skips intro movies)
|
|
#define LF_INSTALLEDTOCACHE 0x00000040 // set if installer populated or validated cache partition
|
|
#define LF_UNKNOWNDATA 0x00000080
|
|
|
|
#pragma pack(1)
|
|
struct launchHeader_t
|
|
{
|
|
unsigned int id;
|
|
unsigned int version;
|
|
unsigned int flags;
|
|
|
|
int nUserID;
|
|
int nCtrlr2Storage[4];
|
|
char nSlot2Ctrlr[4];
|
|
char nSlot2Guest[4];
|
|
int numGameUsers;
|
|
|
|
int bForceEnglish;
|
|
|
|
// increments at each engine re-launch
|
|
DWORD nAttractID;
|
|
|
|
// 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.nUserID = XBX_INVALID_USER_ID;
|
|
m_Launch.header.bForceEnglish = false;
|
|
|
|
m_Launch.header.nCtrlr2Storage[0] = XBX_INVALID_STORAGE_ID;
|
|
m_Launch.header.nCtrlr2Storage[1] = XBX_INVALID_STORAGE_ID;
|
|
m_Launch.header.nCtrlr2Storage[2] = XBX_INVALID_STORAGE_ID;
|
|
m_Launch.header.nCtrlr2Storage[3] = XBX_INVALID_STORAGE_ID;
|
|
|
|
m_Launch.header.nSlot2Ctrlr[0] = 0;
|
|
m_Launch.header.nSlot2Ctrlr[1] = 1;
|
|
m_Launch.header.nSlot2Ctrlr[2] = 2;
|
|
m_Launch.header.nSlot2Ctrlr[3] = 3;
|
|
|
|
m_Launch.header.nSlot2Guest[0] = 0;
|
|
m_Launch.header.nSlot2Guest[1] = 0;
|
|
m_Launch.header.nSlot2Guest[2] = 0;
|
|
m_Launch.header.nSlot2Guest[3] = 0;
|
|
|
|
m_Launch.header.numGameUsers = 0;
|
|
|
|
m_Launch.header.nAttractID = 0;
|
|
|
|
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 defined( _DEMO )
|
|
if ( pData && ( flags & LF_UNKNOWNDATA ) )
|
|
{
|
|
// not ours, put the demo structure back as-is
|
|
XSetLaunchData( pData, dataSize );
|
|
m_LaunchDataSize = dataSize;
|
|
return true;
|
|
}
|
|
#endif
|
|
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;
|
|
}
|
|
}
|
|
else if ( !m_LaunchDataSize )
|
|
{
|
|
// mark for caller as all invalid
|
|
if ( pID )
|
|
{
|
|
*pID = 0;
|
|
}
|
|
if ( pData )
|
|
{
|
|
*pData = NULL;
|
|
}
|
|
if ( pDataSize )
|
|
{
|
|
*pDataSize = 0;
|
|
}
|
|
}
|
|
|
|
// valid when any 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 !defined( _DEMO )
|
|
if ( m_Launch.header.id != VALVE_LAUNCH_ID || m_Launch.header.version != VALVE_LAUNCH_VERSION )
|
|
{
|
|
// not interested in somebody else's data
|
|
ResetLaunchData();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Returns OUR internal launch flags.
|
|
//--------------------------------------------------------------------------------------
|
|
int GetLaunchFlags()
|
|
{
|
|
// establish the data
|
|
RestoreOrResetLaunchData();
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
return m_Launch.header.flags;
|
|
}
|
|
|
|
void SetLaunchFlags( unsigned int ufNewFlags )
|
|
{
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
m_Launch.header.flags = ufNewFlags;
|
|
}
|
|
|
|
void GetStorageID( int storageID[4] )
|
|
{
|
|
RestoreOrResetLaunchData();
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
storageID[0] = XBX_INVALID_STORAGE_ID;
|
|
storageID[1] = XBX_INVALID_STORAGE_ID;
|
|
storageID[2] = XBX_INVALID_STORAGE_ID;
|
|
storageID[3] = XBX_INVALID_STORAGE_ID;
|
|
return;
|
|
}
|
|
#endif
|
|
memcpy( storageID, m_Launch.header.nCtrlr2Storage, sizeof( m_Launch.header.nCtrlr2Storage ) );
|
|
}
|
|
void SetStorageID( int const storageID[4] )
|
|
{
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
memcpy( m_Launch.header.nCtrlr2Storage, storageID, sizeof( m_Launch.header.nCtrlr2Storage ) );
|
|
}
|
|
|
|
void GetSlotUsers( int &numGameUsers, char nSlot2Ctrlr[4], char nSlot2Guest[4] )
|
|
{
|
|
RestoreOrResetLaunchData();
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
numGameUsers = 0;
|
|
|
|
nSlot2Ctrlr[0] = 0;
|
|
nSlot2Ctrlr[1] = 1;
|
|
nSlot2Ctrlr[2] = 2;
|
|
nSlot2Ctrlr[3] = 3;
|
|
|
|
nSlot2Guest[0] = 0;
|
|
nSlot2Guest[1] = 0;
|
|
nSlot2Guest[2] = 0;
|
|
nSlot2Guest[3] = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
numGameUsers = m_Launch.header.numGameUsers;
|
|
memcpy( nSlot2Ctrlr, m_Launch.header.nSlot2Ctrlr, sizeof( m_Launch.header.nSlot2Ctrlr ) );
|
|
memcpy( nSlot2Guest, m_Launch.header.nSlot2Guest, sizeof( m_Launch.header.nSlot2Guest ) );
|
|
}
|
|
void SetSlotUsers( int numGameUsers, char const nSlot2Ctrlr[4], char const nSlot2Guest[4] )
|
|
{
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
m_Launch.header.numGameUsers = numGameUsers;
|
|
memcpy( m_Launch.header.nSlot2Ctrlr, nSlot2Ctrlr, sizeof( m_Launch.header.nSlot2Ctrlr ) );
|
|
memcpy( m_Launch.header.nSlot2Guest, nSlot2Guest, sizeof( m_Launch.header.nSlot2Guest ) );
|
|
}
|
|
|
|
int GetUserID( void )
|
|
{
|
|
RestoreOrResetLaunchData();
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return XBX_INVALID_USER_ID;
|
|
}
|
|
#endif
|
|
return m_Launch.header.nUserID;
|
|
}
|
|
void SetUserID( int userID )
|
|
{
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
m_Launch.header.nUserID = userID;
|
|
}
|
|
|
|
bool GetForceEnglish( void )
|
|
{
|
|
RestoreOrResetLaunchData();
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
return m_Launch.header.bForceEnglish ? true : false;
|
|
}
|
|
void SetForceEnglish( bool bForceEnglish )
|
|
{
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
m_Launch.header.bForceEnglish = bForceEnglish;
|
|
}
|
|
|
|
DWORD GetAttractID( void )
|
|
{
|
|
RestoreOrResetLaunchData();
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
return m_Launch.header.nAttractID;
|
|
}
|
|
void SetAttractID( DWORD nAttractID )
|
|
{
|
|
#if defined( _DEMO )
|
|
if ( m_Launch.header.id && m_Launch.header.id != VALVE_LAUNCH_ID )
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
m_Launch.header.nAttractID = nAttractID;
|
|
}
|
|
|
|
void Launch( const char *pNewImageName = NULL )
|
|
{
|
|
if ( !pNewImageName )
|
|
{
|
|
#if defined( _DEMO )
|
|
pNewImageName = XLAUNCH_KEYWORD_DEFAULT_APP;
|
|
#else
|
|
pNewImageName = "default.xex";
|
|
#endif
|
|
}
|
|
|
|
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
|