|
|
//========= 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
|