SteamControllerInterface::~SteamControllerInterface()
{
	if(SteamController() != NULL)
	{
		SteamController()->Shutdown();
	}
}
	virtual ~FSteamController()
	{
		if (SteamController() != nullptr)
		{
			SteamController()->Shutdown();
		}
	}
SteamControllerInterface::SteamControllerInterface( const TSharedRef< FGenericApplicationMessageHandler >& InMessageHandler )
	: MessageHandler( InMessageHandler )
{
	if(SteamController() != NULL)
	{
		FString vdfPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*FPaths::GeneratedConfigDir(), TEXT("controller.vdf")));
		bool bInited = SteamController()->Init(TCHAR_TO_ANSI(*vdfPath));
		UE_LOG(LogSteamController, Log, TEXT("SteamController %s initialized with vdf file '%s'."), bInited ? TEXT("could not be") : TEXT("has been"), *vdfPath);

		// [RCL] 2014-05-05 FIXME: disable when could not init?
		if (bInited)
		{
			FMemory::MemZero(ControllerStates);
		}
	}
	else
	{
		UE_LOG(LogSteamController, Log, TEXT("SteamController is not available"));
	}

	InitialButtonRepeatDelay = 0.2f;
	ButtonRepeatDelay = 0.1f;

	Buttons[0] = EControllerButtons::FaceButtonBottom;
	Buttons[1] = EControllerButtons::FaceButtonRight;
	Buttons[2] = EControllerButtons::FaceButtonLeft;
	Buttons[3] = EControllerButtons::FaceButtonTop;
	Buttons[4] = EControllerButtons::LeftShoulder;
	Buttons[5] = EControllerButtons::RightShoulder;
	Buttons[6] = EControllerButtons::SpecialRight;
	Buttons[7] = EControllerButtons::SpecialLeft;
	Buttons[8] = EControllerButtons::LeftThumb;
	Buttons[9] = EControllerButtons::RightThumb;
	Buttons[10] = EControllerButtons::LeftTriggerThreshold;
	Buttons[11] = EControllerButtons::RightTriggerThreshold;
	Buttons[12] = EControllerButtons::Touch0;
	Buttons[13] = EControllerButtons::Touch1;
	Buttons[14] = EControllerButtons::Touch2;
	Buttons[15] = EControllerButtons::Touch3;
	Buttons[16] = EControllerButtons::LeftStickUp;
	Buttons[17] = EControllerButtons::LeftStickDown;
	Buttons[18] = EControllerButtons::LeftStickLeft;
	Buttons[19] = EControllerButtons::LeftStickRight;
	Buttons[20] = EControllerButtons::RightStickUp;
	Buttons[21] = EControllerButtons::RightStickDown;
	Buttons[22] = EControllerButtons::RightStickLeft;
	Buttons[23] = EControllerButtons::RightStickRight;
	Buttons[24] = EControllerButtons::BackLeft;
	Buttons[25] = EControllerButtons::BackRight;
}
예제 #4
0
	void deinit()
	{
		// Shutdown the SteamAPI
		SteamController()->Shutdown();
		SteamAPI_Shutdown();

		// Delete the SteamAchievements object
		if (g_SteamAchievements)
			delete g_SteamAchievements;

		// Shutdown Steam CEG
		Steamworks_TermCEGLibrary();
	}
	void UpdateVibration(int32 ControllerId)
	{
		const FControllerState& ControllerState = ControllerStates[ControllerId];
		ISteamController* const Controller = SteamController();

		// Map the float values from [0,1] to be more reasonable values for the SteamController.  The docs say that [100,2000] are reasonable values
 		const float LeftIntensity = FMath::Clamp(ControllerState.VibeValues.LeftLarge * 2000.f, 0.f, 2000.f);
		if (LeftIntensity > 0.f)
		{
			Controller->TriggerHapticPulse(ControllerId, ESteamControllerPad::k_ESteamControllerPad_Left, LeftIntensity);
		}
 
 		const float RightIntensity = FMath::Clamp(ControllerState.VibeValues.RightLarge * 2000.f, 0.f, 2000.f);
		if (RightIntensity > 0.f)
		{
			Controller->TriggerHapticPulse(ControllerId, ESteamControllerPad::k_ESteamControllerPad_Right, RightIntensity);
		}
	}
	void UpdateVibration(int32 ControllerId)
	{
		// make sure there is a valid device for this controller
		ISteamController* const Controller = SteamController();
		if (Controller == nullptr || IsGamepadAttached() == false)
		{
			return;
		}

		const FControllerState& ControllerState = ControllerStates[ControllerId];

		// Map the float values from [0,1] to be more reasonable values for the SteamController.  The docs say that [100,2000] are reasonable values
 		const float LeftIntensity = FMath::Clamp(ControllerState.VibeValues.LeftLarge * 2000.f, 0.f, 2000.f);
		if (LeftIntensity > 0.f)
		{
			Controller->TriggerHapticPulse(ControllerId, ESteamControllerPad::k_ESteamControllerPad_Left, LeftIntensity);
		}
 
 		const float RightIntensity = FMath::Clamp(ControllerState.VibeValues.RightLarge * 2000.f, 0.f, 2000.f);
		if (RightIntensity > 0.f)
		{
			Controller->TriggerHapticPulse(ControllerId, ESteamControllerPad::k_ESteamControllerPad_Right, RightIntensity);
		}
	}
예제 #7
0
static int RealMain( const char *pchCmdLine, HINSTANCE hInstance, int nCmdShow )
{

    if ( SteamAPI_RestartAppIfNecessary( k_uAppIdInvalid ) )
    {
        // if Steam is not running or the game wasn't started through Steam, SteamAPI_RestartAppIfNecessary starts the
        // local Steam client and also launches this game again.

        // Once you get a public Steam AppID assigned for this game, you need to replace k_uAppIdInvalid with it and
        // removed steam_appid.txt from the game depot.

        return EXIT_FAILURE;
    }


    // Init Steam CEG
    if ( !Steamworks_InitCEGLibrary() )
    {
        OutputDebugString( "Steamworks_InitCEGLibrary() failed\n" );
        Alert( "Fatal Error", "Steam must be running to play this game (InitDrmLibrary() failed).\n" );
        return EXIT_FAILURE;
    }

    // Initialize SteamAPI, if this fails we bail out since we depend on Steam for lots of stuff.
    // You don't necessarily have to though if you write your code to check whether all the Steam
    // interfaces are NULL before using them and provide alternate paths when they are unavailable.
    //
    // This will also load the in-game steam overlay dll into your process.  That dll is normally
    // injected by steam when it launches games, but by calling this you cause it to always load,
    // even when not launched via steam.
    if ( !SteamAPI_Init() )
    {
        OutputDebugString( "SteamAPI_Init() failed\n" );
        Alert( "Fatal Error", "Steam must be running to play this game (SteamAPI_Init() failed).\n" );
        return EXIT_FAILURE;
    }

    // set our debug handler
    SteamClient()->SetWarningMessageHook( &SteamAPIDebugTextHook );

    // Tell Steam where it's overlay should show notification dialogs, this can be top right, top left,
    // bottom right, bottom left. The default position is the bottom left if you don't call this.
    // Generally you should use the default and not call this as users will be most comfortable with
    // the default position.  The API is provided in case the bottom right creates a serious conflict
    // with important UI in your game.
    SteamUtils()->SetOverlayNotificationPosition( k_EPositionTopRight );

    // Ensure that the user has logged into Steam. This will always return true if the game is launched
    // from Steam, but if Steam is at the login prompt when you run your game from the debugger, it
    // will return false.
    if ( !SteamUser()->BLoggedOn() )
    {
        OutputDebugString( "Steam user is not logged in\n" );
        Alert( "Fatal Error", "Steam user must be logged in to play this game (SteamUser()->BLoggedOn() returned false).\n" );
        return EXIT_FAILURE;
    }

    // We are going to use the controller interface, initialize it, which is a seperate step as it
    // create a new thread in the game proc and we don't want to force that on games that don't
    // have native Steam controller implementations

    char rgchCWD[1024];
    _getcwd( rgchCWD, sizeof( rgchCWD ) );

    char rgchFullPath[1024];
#if defined(_WIN32)
    _snprintf( rgchFullPath, sizeof( rgchFullPath ), "%s\\%s", rgchCWD, "controller.vdf" );
#elif defined(OSX)
    // hack for now, because we do not have utility functions available for finding the resource path
    // alternatively we could disable the SteamController init on OS X
    _snprintf( rgchFullPath, sizeof( rgchFullPath ), "%s/steamworksexample.app/Contents/Resources/%s", rgchCWD, "controller.vdf" );
#else
    _snprintf( rgchFullPath, sizeof( rgchFullPath ), "%s/%s", rgchCWD, "controller.vdf" );
#endif
    if( !SteamController()->Init( rgchFullPath ) )
    {
        OutputDebugString( "SteamController()->Init() failed\n" );
        Alert( "Fatal Error", "Steam Controller Init failed. Is controller.vdf in the current working directory?\n" );
        return EXIT_FAILURE;
    }

    bool bUseVR = SteamUtils()->IsSteamRunningInVR();
    const char *pchServerAddress, *pchLobbyID;
    ParseCommandLine( pchCmdLine, &pchServerAddress, &pchLobbyID, &bUseVR );

    // do a DRM self check
    Steamworks_SelfCheck();

    // init VR before we make the window

    // Construct a new instance of the game engine
    // bugbug jmccaskey - make screen resolution dynamic, maybe take it on command line?
    IGameEngine *pGameEngine =
#if defined(_WIN32)
        new CGameEngineWin32( hInstance, nCmdShow, 1024, 768, bUseVR );
#elif defined(OSX)
        CreateGameEngineOSX();
#elif defined(SDL)
        CreateGameEngineSDL( bUseVR );
#else
#error	Need CreateGameEngine()
#endif

    // This call will block and run until the game exits
    RunGameLoop( pGameEngine, pchServerAddress, pchLobbyID );

    // Shutdown the SteamAPI
    SteamController()->Shutdown();
    SteamAPI_Shutdown();

    // Shutdown Steam CEG
    Steamworks_TermCEGLibrary();

    // exit
    return EXIT_SUCCESS;
}
	FSteamController(const TSharedRef< FGenericApplicationMessageHandler >& InMessageHandler)
		: MessageHandler(InMessageHandler)
	{
		// Attempt to load the Steam Library
		if (!LoadSteamModule())
		{
			return;
		}

		// Initialize the API, so we can start calling SteamController functions
		bool bAPIInitialized = SteamAPI_Init();

			// [RCL] 2015-01-23 FIXME: move to some other code than constructor so we can handle failures more gracefully
		if (bAPIInitialized && (SteamController() != nullptr))
		{
			FString PluginsDir = FPaths::EnginePluginsDir();
			FString ContentDir = FPaths::Combine(*PluginsDir, TEXT("Runtime"), TEXT("Steam"), TEXT("SteamController"), TEXT("Content"));
			FString VdfPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(*ContentDir, TEXT("Controller.vdf")));

			bool bInited = SteamController()->Init(TCHAR_TO_ANSI(*VdfPath));
			UE_LOG(LogSteamController, Log, TEXT("SteamController %s initialized with vdf file '%s'."), bInited ? TEXT("could not be") : TEXT("has been"), *VdfPath);

			// [RCL] 2014-05-05 FIXME: disable when could not init?
			if (bInited)
			{
				FMemory::Memzero(ControllerStates, sizeof(ControllerStates));
			}
		}
		else
		{
			UE_LOG(LogSteamController, Log, TEXT("SteamController is not available"));
		}

		InitialButtonRepeatDelay = 0.2f;
		ButtonRepeatDelay = 0.1f;

		// set up mapping
		Buttons[0] = FGamepadKeyNames::FaceButtonBottom;
		Buttons[1] = FGamepadKeyNames::FaceButtonRight;
		Buttons[2] = FGamepadKeyNames::FaceButtonLeft;
		Buttons[3] = FGamepadKeyNames::FaceButtonTop;
		Buttons[4] = FGamepadKeyNames::LeftShoulder;
		Buttons[5] = FGamepadKeyNames::RightShoulder;
		Buttons[6] = FGamepadKeyNames::SpecialRight;
		Buttons[7] = FGamepadKeyNames::SpecialLeft;
		Buttons[8] = FGamepadKeyNames::LeftThumb;
		Buttons[9] = FGamepadKeyNames::RightThumb;
		Buttons[10] = FGamepadKeyNames::LeftTriggerThreshold;
		Buttons[11] = FGamepadKeyNames::RightTriggerThreshold;
		Buttons[12] = SteamControllerKeyNames::Touch0;
		Buttons[13] = SteamControllerKeyNames::Touch1;
		Buttons[14] = SteamControllerKeyNames::Touch2;
		Buttons[15] = SteamControllerKeyNames::Touch3;
		Buttons[16] = FGamepadKeyNames::LeftStickUp;
		Buttons[17] = FGamepadKeyNames::LeftStickDown;
		Buttons[18] = FGamepadKeyNames::LeftStickLeft;
		Buttons[19] = FGamepadKeyNames::LeftStickRight;
		Buttons[20] = FGamepadKeyNames::RightStickUp;
		Buttons[21] = FGamepadKeyNames::RightStickDown;
		Buttons[22] = FGamepadKeyNames::RightStickLeft;
		Buttons[23] = FGamepadKeyNames::RightStickRight;
		Buttons[24] = SteamControllerKeyNames::BackLeft;
		Buttons[25] = SteamControllerKeyNames::BackLeft;
	}
	virtual void SendControllerEvents() override
	{
		SteamControllerState_t ControllerState;

		if (SteamController() != nullptr)
		{
			const double CurrentTime = FPlatformTime::Seconds();

			for (uint32 ControllerIndex=0; ControllerIndex < MAX_STEAM_CONTROLLERS; ++ControllerIndex)
			{
				if (SteamController()->GetControllerState(ControllerIndex, &ControllerState))
				{
					if (ControllerState.unPacketNum != ControllerStates[ControllerIndex].PacketNum )
					{
						bool CurrentStates[MAX_NUM_CONTROLLER_BUTTONS] = {0};
			
						// Get the current state of all buttons
						CurrentStates[0] = !!(ControllerState.ulButtons & STEAM_BUTTON_3_MASK);
						CurrentStates[1] = !!(ControllerState.ulButtons & STEAM_BUTTON_1_MASK);
						CurrentStates[2] = !!(ControllerState.ulButtons & STEAM_BUTTON_2_MASK);
						CurrentStates[3] = !!(ControllerState.ulButtons & STEAM_BUTTON_0_MASK);
						CurrentStates[4] = !!(ControllerState.ulButtons & STEAM_LEFT_BUMPER_MASK);
						CurrentStates[5] = !!(ControllerState.ulButtons & STEAM_RIGHT_BUMPER_MASK);
						CurrentStates[6] = !!(ControllerState.ulButtons & STEAM_BUTTON_ESCAPE_MASK);
						CurrentStates[7] = !!(ControllerState.ulButtons & STEAM_BUTTON_MENU_MASK);
						CurrentStates[8] = !!(ControllerState.ulButtons & STEAM_BUTTON_LEFTPAD_CLICKED_MASK);
						CurrentStates[9] = !!(ControllerState.ulButtons & STEAM_BUTTON_RIGHTPAD_CLICKED_MASK);
						CurrentStates[10] = !!(ControllerState.ulButtons & STEAM_LEFT_TRIGGER_MASK);
						CurrentStates[11] = !!(ControllerState.ulButtons & STEAM_RIGHT_TRIGGER_MASK);
						CurrentStates[12] = !!(ControllerState.ulButtons & STEAM_TOUCH_0_MASK);
						CurrentStates[13] = !!(ControllerState.ulButtons & STEAM_TOUCH_1_MASK);
						CurrentStates[14] = !!(ControllerState.ulButtons & STEAM_TOUCH_2_MASK);
						CurrentStates[15] = !!(ControllerState.ulButtons & STEAM_TOUCH_3_MASK);
						CurrentStates[16] = !!(ControllerState.sLeftPadY > LEFT_THUMBPAD_DEADZONE);
						CurrentStates[17] = !!(ControllerState.sLeftPadY < -LEFT_THUMBPAD_DEADZONE);
						CurrentStates[18] = !!(ControllerState.sLeftPadX < -LEFT_THUMBPAD_DEADZONE);
						CurrentStates[19] = !!(ControllerState.sLeftPadX > LEFT_THUMBPAD_DEADZONE);
						CurrentStates[20] = !!(ControllerState.sRightPadY > RIGHT_THUMBPAD_DEADZONE);
						CurrentStates[21] = !!(ControllerState.sRightPadY < -RIGHT_THUMBPAD_DEADZONE);
						CurrentStates[22] = !!(ControllerState.sRightPadX < -RIGHT_THUMBPAD_DEADZONE);
						CurrentStates[23] = !!(ControllerState.sRightPadX > RIGHT_THUMBPAD_DEADZONE);
						CurrentStates[24] = !!(ControllerState.ulButtons & STEAM_BUTTON_BACK_LEFT_MASK);
						CurrentStates[25] = !!(ControllerState.ulButtons & STEAM_BUTTON_BACK_RIGHT_MASK);

						if (ControllerStates[ControllerIndex].LeftXAnalog != ControllerState.sLeftPadX)
						{
							MessageHandler->OnControllerAnalog(FGamepadKeyNames::LeftAnalogX, ControllerIndex, ShortToNormalizedFloat(ControllerState.sLeftPadX));
							ControllerStates[ControllerIndex].LeftXAnalog = ControllerState.sLeftPadX;
						}

						if (ControllerStates[ControllerIndex].LeftYAnalog != ControllerState.sLeftPadY)
						{
							MessageHandler->OnControllerAnalog(FGamepadKeyNames::LeftAnalogY, ControllerIndex, ShortToNormalizedFloat(ControllerState.sLeftPadY));
							ControllerStates[ControllerIndex].LeftYAnalog = ControllerState.sLeftPadY;
						}

						if (ControllerStates[ControllerIndex].RightXAnalog != ControllerState.sRightPadX)
						{
							MessageHandler->OnControllerAnalog(FGamepadKeyNames::RightAnalogX, ControllerIndex, ShortToNormalizedFloat(ControllerState.sRightPadX));
							ControllerStates[ControllerIndex].RightXAnalog = ControllerState.sRightPadX;
						}

						if (ControllerStates[ControllerIndex].RightYAnalog != ControllerState.sRightPadY)
						{
							MessageHandler->OnControllerAnalog(FGamepadKeyNames::RightAnalogY, ControllerIndex, ShortToNormalizedFloat(ControllerState.sRightPadY));
							ControllerStates[ControllerIndex].RightYAnalog = ControllerState.sRightPadY;
						}


						// For each button check against the previous state and send the correct message if any
						for (int32 ButtonIndex = 0; ButtonIndex < MAX_NUM_CONTROLLER_BUTTONS; ++ButtonIndex)
						{
							if (CurrentStates[ButtonIndex] != ControllerStates[ControllerIndex].ButtonStates[ButtonIndex])
							{
								if (CurrentStates[ButtonIndex])
								{
									MessageHandler->OnControllerButtonPressed(Buttons[ButtonIndex], ControllerIndex, false);
								}
								else
								{
									MessageHandler->OnControllerButtonReleased(Buttons[ButtonIndex], ControllerIndex, false);
								}

								if (CurrentStates[ButtonIndex] != 0)
								{
									// this button was pressed - set the button's NextRepeatTime to the InitialButtonRepeatDelay
									ControllerStates[ControllerIndex].NextRepeatTime[ButtonIndex] = CurrentTime + InitialButtonRepeatDelay;
								}
							}

							// Update the state for next time
							ControllerStates[ControllerIndex].ButtonStates[ButtonIndex] = CurrentStates[ButtonIndex];
						}

						ControllerStates[ControllerIndex].PacketNum = ControllerState.unPacketNum;
					}
				}

				for (int32 ButtonIndex = 0; ButtonIndex < MAX_NUM_CONTROLLER_BUTTONS; ++ButtonIndex)
				{
					if (ControllerStates[ControllerIndex].ButtonStates[ButtonIndex] != 0 && ControllerStates[ControllerIndex].NextRepeatTime[ButtonIndex] <= CurrentTime)
					{
						MessageHandler->OnControllerButtonPressed(Buttons[ButtonIndex], ControllerIndex, true);

						// set the button's NextRepeatTime to the ButtonRepeatDelay
						ControllerStates[ControllerIndex].NextRepeatTime[ButtonIndex] = CurrentTime + ButtonRepeatDelay;
					}
				}
			}
		}
	}
예제 #10
0
bool SteamVR::Init()
{
  if (SteamAPI_RestartAppIfNecessary(k_uAppIdInvalid))
  {
    // if Steam is not running or the game wasn't started through Steam, SteamAPI_RestartAppIfNecessary starts the 
    // local Steam client and also launches this game again.

    // Once you get a public Steam AppID assigned for this game, you need to replace k_uAppIdInvalid with it and
    // removed steam_appid.txt from the game depot.
    return false;
  }

  if (!SteamAPI_Init())
  {
    Log("SteamAPI_Init() failed\n");
    return false;
  }

  // set our debug handler
  //SteamClient()->SetWarningMessageHook(&SteamAPIDebugTextHook);

  // Ensure that the user has logged into Steam. This will always return true if the game is launched
  // from Steam, but if Steam is at the login prompt when you run your game from the debugger, it
  // will return false.
  if (!SteamUser()->BLoggedOn())
  {
    Log("Steam user is not logged in\n");
    Log("Steam user must be logged in to play this game (SteamUser()->BLoggedOn() returned false).\n");
    return false;
  }

  // Initialize steam controller if connected
  char rgchCWD[1024];
  _getcwd(rgchCWD, sizeof(rgchCWD));

  char rgchFullPath[1024];
  _snprintf(rgchFullPath, sizeof(rgchFullPath), "%s\\%s", rgchCWD, "controller.vdf");

  if (!SteamController()->Init(rgchFullPath))
  {
    Log("SteamController()->Init() failed\n");
    Log("Steam Controller Init failed. Is controller.vdf in the current working directory?\n");
    return false;
  }

  // Need to run from Steam UI to work I think
  bool UseVR = SteamUtils()->IsSteamRunningInVR();
  // Set UseVR to true for testing
  UseVR = true;

  // Init VR
  if (!UseVR)
  {
    mVRHmd = NULL;
  }
  else
  {
    vr::HmdError error;
    mVRHmd = vr::VR_Init(&error);
    if (!mVRHmd)
    {
      Log("Failed to initialize VR.");
      Log("Game will run without VR.");
      return false;
    }
  }

  Log("SteamVR Initialized");
  return true;
}
예제 #11
0
	void init(const std::vector<AchievementInfo>& achievementInfos) //const char *pchCmdLine, HINSTANCE hInstance, int nCmdShow)
	{
		g_AchievementInfosCopy = achievementInfos;
		for (size_t i = 0; i < achievementInfos.size(); ++i)
		{
			Achievement_t achievementData;
			achievementData.m_eAchievementID = i;
			achievementData.m_pchAchievementID = g_AchievementInfosCopy[i].id.c_str();
			strncpy(achievementData.m_rgchName, g_AchievementInfosCopy[i].name.c_str(), 128);
			strncpy(achievementData.m_rgchDescription, g_AchievementInfosCopy[i].description.c_str(), 128);
			achievementData.m_bAchieved = false;
			achievementData.m_iIconImage = 0;
			g_Achievements.push_back(achievementData);
		}

		if (SteamAPI_RestartAppIfNecessary(k_uAppIdInvalid))
		{
			// if Steam is not running or the game wasn't started through Steam, SteamAPI_RestartAppIfNecessary starts the
			// local Steam client and also launches this game again.

			// Once you get a public Steam AppID assigned for this game, you need to replace k_uAppIdInvalid with it and
			// removed steam_appid.txt from the game depot.

			AssertMessage(false, "SteamAPI_RestartAppIfNecessary failed");
		}

		// Init Steam CEG
		if (!Steamworks_InitCEGLibrary())
		{
			Utils::sleepMs(1000);
			if (!Steamworks_InitCEGLibrary()) // try twice - it may be a glitch in the network?
			{
				AssertMessage(false, "Steam must be running to play this game (InitDrmLibrary() failed).");
			}
		}

		// Initialize SteamAPI, if this fails we bail out since we depend on Steam for lots of stuff.
		// You don't necessarily have to though if you write your code to check whether all the Steam
		// interfaces are NULL before using them and provide alternate paths when they are unavailable.
		//
		// This will also load the in-game steam overlay dll into your process.  That dll is normally
		// injected by steam when it launches games, but by calling this you cause it to always load,
		// even when not launched via steam.
		if (!SteamAPI_Init())
		{
			Utils::sleepMs(1000);
			if (!SteamAPI_Init())
			{
				AssertMessage(false, "Steam must be running to play this game (SteamAPI_Init() failed).\n");
			}
		}

		// Create the SteamAchievements object if Steam was successfully initialized
		g_SteamAchievements = new CSteamAchievements(&g_Achievements[0], g_Achievements.size());


		bool res = g_SteamAchievements->RequestStats();
		if (!res)
		{
			Utils::sleepMs(1000);
			res = g_SteamAchievements->RequestStats();
			if (!res)
			{
				AssertMessage(false, "Could not get stats from Steam.\nPlease check that your Internet connection is working correctly and that Steam is up.\n");
			}
		}


		// set our debug handler
		SteamClient()->SetWarningMessageHook(&SteamAPIDebugTextHook);

		// Tell Steam where it's overlay should show notification dialogs, this can be top right, top left,
		// bottom right, bottom left. The default position is the bottom left if you don't call this.
		// Generally you should use the default and not call this as users will be most comfortable with
		// the default position.  The API is provided in case the bottom right creates a serious conflict
		// with important UI in your game.
		SteamUtils()->SetOverlayNotificationPosition(k_EPositionTopRight);

		// Ensure that the user has logged into Steam. This will always return true if the game is launched
		// from Steam, but if Steam is at the login prompt when you run your game from the debugger, it
		// will return false.
		if (!SteamUser()->BLoggedOn())
		{
			Utils::sleepMs(1000);
			if (!SteamUser()->BLoggedOn())
			{
				AssertMessage(false, "Steam user must be logged in to play this game (SteamUser()->BLoggedOn() returned false).\n");
			}
		}

		// We are going to use the controller interface, initialize it, which is a seperate step as it
		// create a new thread in the game proc and we don't want to force that on games that don't
		// have native Steam controller implementations

#ifdef USES_LINUX
		std::string rgchCWDstr = Utils::convertWStringToString(Utils::getCurrentDirectoryUnicode(), true);
		const char* rgchCWD = rgchCWDstr.c_str();
#else
		char rgchCWD[1024];
		_getcwd( rgchCWD, sizeof( rgchCWD ) );
#endif

		char rgchFullPath[1024];
#if defined(_WIN32)
		_snprintf(rgchFullPath, sizeof(rgchFullPath), "%s\\%s", rgchCWD, "controller.vdf");//.c_str()
#elif defined(OSX)
		// hack for now, because we do not have utility functions available for finding the resource path
		// alternatively we could disable the SteamController init on OS X
		_snprintf(rgchFullPath, sizeof(rgchFullPath), "%s/steamworksexample.app/Contents/Resources/%s", rgchCWD, "controller.vdf");
#else
		_snprintf(rgchFullPath, sizeof(rgchFullPath), "%s/%s", rgchCWD, "controller.vdf");
#endif
		if (!SteamController()->Init(rgchFullPath))
		{
			AssertMessage(false, "Steam Controller Init failed. Is controller.vdf in the current working directory?\n");
		}

		/*bool bUseVR = SteamUtils()->IsSteamRunningInVR();
		const char *pchServerAddress, *pchLobbyID;
		ParseCommandLine(pchCmdLine, &pchServerAddress, &pchLobbyID, &bUseVR);*/

		// do a DRM self check
		Steamworks_SelfCheck();

		// init VR before we make the window

		// Construct a new instance of the game engine
		// bugbug jmccaskey - make screen resolution dynamic, maybe take it on command line?
		/*IGameEngine *pGameEngine =
#if defined(_WIN32)
			new CGameEngineWin32(hInstance, nCmdShow, 1024, 768, bUseVR);
#elif defined(OSX)
			CreateGameEngineOSX();
#elif defined(SDL)
			CreateGameEngineSDL(bUseVR);
#else
#error	Need CreateGameEngine()
#endif*/
	}