MetaXR Platform Implementation
This page documents how we approach using the MetaXR Platform features to get information related to the user's Oculus/Meta account, such as username and subscription information. This is already built into our SDK and implemented as a component on the Cognitive3D actor blueprint, and all you have to do to make use of these features is follow the steps in Third Party SDK Features to activate it in the build file.
Prerequisites
Using the Meta Social Platform requires you to have the MetaXR Platform plugin downloaded from here(link) for the appropriate version of UE5 that you are using and then placing it in the Engine's Marketplace Plugin folder, as per the instructions in the link. This will have to then be activated in the project's Plugin tab.
To use this feature with UE4, you need to use the Oculus-VR fork of UE4 found on the Oculus-VR GitHub repo, which includes an appropriate version of the MetaXR Platform plugin.
Note
The implementation for using OculusId to uniquely identify users is automated with the provided components. The sections below are included for completeness, but you do not need to do any additional work beyond enabling the Meta Platform SDK in the Cognitive3D.Build.cs file outlined above and enabling platform access on the Quest Dashboard.
MetaXR Platform: C++
To get MetaXR Platform implemented in C++ and avoid using blueprints, follow these steps and your code will be able to make requests and capture the response messages as needed.
First, we need to initialize the platform for deployment on Android. The reason we do not initialize it for windows is that capturing Meta Platform responses only works when the app is deployed to the HMD through Meta Quest Developer Hub, and is used by an entitled user.
Add this code to the Actor class you are using to capture this information:
#include "OVRPlatform.h"
#include "OVR_Platform.h"
#include "OVRPlatformSubsystem.h"
#include "OVRPlatformSDK.cpp"
#ifdef __ANDROID__
#include "Android/AndroidApplication.h"
#endif
//....
//in begin play we initialize the platform for Android:
#ifdef __ANDROID__
JNIEnv* Env = FAndroidApplication::GetJavaEnv();
jobject Activity = FAndroidApplication::GetGameActivityThis();
FString EngineIni = FPaths::Combine(*(FPaths::ProjectDir()), TEXT("Config/DefaultEngine.ini"));
FString OculusAppId = FAnalytics::Get().GetConfigValueFromIni(EngineIni, "OnlineSubsystemOculus", "OculusAppId", false);
auto tempAnsi = StringCast<ANSICHAR>(*OculusAppId);
const char* AppID = tempAnsi.Get();
if (Env != nullptr && Activity != nullptr)
{
ovrPlatformInitializeResult result = ovr_PlatformInitializeAndroid(AppID, Activity, Env);
if (result != ovrPlatformInitialize_Success)
{
// Handle initialization failure
UE_LOG(LogTemp, Error, TEXT("Failed to initialize Oculus Platform, Error code: %d"), result);
}
else
{
// Initialization successful
UE_LOG(LogTemp, Log, TEXT("Oculus Platform initialized successfully"));
}
}
#endif
Assuming this code initializes properly, we then initialize the subsystem and start the message pump, then we can start making requests for the different platform components we need. Once a request is made, we listen for that response message associated with it in our Tick function and handle that accordingly.
//initialize the subsystem and start the message pump
//platform initialization for the subsystem is initialized in the game instance
UGameInstance* GameInstance = GetOwner()->GetGameInstance();
UOvrPlatformSubsystem* ovrSubsystem = GameInstance->GetSubsystem<UOvrPlatformSubsystem>();
ovrSubsystem->StartMessagePump();
//request to get the entitlement status
ovr_Entitlement_GetIsViewerEntitled();
// get the logged in user's id
// this is not a request, so it returns the data directly
ovrID loggedInUserID = ovr_GetLoggedInUserID();
//initiate a request to get the logged in users's information
// this is a request, so the response is returned on the message queue
ovr_User_Get(loggedInUserID);
//request to get access token
gotAccessToken = false;
ovr_User_GetAccessToken();
//...
//in our tick function:
ovrMessageHandle Message;
while ((Message = ovr_PopMessage()) != nullptr)
{
if (ovr_Message_GetType(Message) == ovrMessage_Entitlement_GetIsViewerEntitled)
{
if (ovr_Message_IsError(Message))
{
ovrErrorHandle Error = ovr_Message_GetError(Message);
const char* ErrorMessage = ovr_Error_GetMessage(Error);
UE_LOG(LogTemp, Error, TEXT("User is not entitled: %s"), *FString(ErrorMessage));
}
else //user is entitled
{
}
}
if (ovr_Message_GetType(Message) == ovrMessage_User_Get)
{
if (ovr_Message_IsError(Message))
{
// Error handling
ovrErrorHandle Error = ovr_Message_GetError(Message);
const char* ErrorMessage = ovr_Error_GetMessage(Error);
UE_LOG(LogTemp, Error, TEXT("Failed to retrieve user: %s"), *FString(ErrorMessage));
}
else
{
// Handle the user data
HandleUserRetrieved(Message);
}
}
if (ovr_Message_GetType(Message) == ovrMessage_User_GetAccessToken)
{
if (ovr_Message_IsError(Message))
{
//error handling
ovrErrorHandle Error = ovr_Message_GetError(Message);
const char* ErrorMessage = ovr_Error_GetMessage(Error);
UE_LOG(LogTemp, Error, TEXT("Failed to retrieve access token: %s"), *FString(ErrorMessage));
}
else
{
//handle access token
HandleAccessToekenRetrieved(Message);
}
}
}
Once we get a response for the specific message type we are looking for, we want to extract the payload from that message. The message type to listen for as well as the payload expected for each request is detailed in the source code of the plugin for each request function, found in OVR_Platform.h
void UOculusPlatform::HandleUserRetrieved(const ovrMessageHandle Message)
{
ovrUserHandle User = ovr_Message_GetUser(Message);
const char* UserName = ovr_User_GetDisplayName(User);
ovrID oculusID = ovr_User_GetID(User);
}
void UOculusPlatform::HandleAccessToekenRetrieved(const ovrMessageHandle Message)
{
const char* AccessToken = ovr_Message_GetString(Message);
}
MetaXR Platform: Blueprints
To use the Meta Social Platform in your application and send those Oculus Identity session properties to the dashboard, you can paste the text in this file into your Game Instance blueprint only. Do not put this in another Blueprint as it will not function as intended.