source-engine/common/xbox/xbox_launch.h

296 lines
7.8 KiB
C
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= 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