Sessions (Per-round) for VIVEPORT Arcade API

The VIVEPORT Arcade Sessions API provides an easy way for the content to notify the VIVEPORT Arcade system that a session was started and stopped.

How to use Sessions API

Note

  1. Remember that you should call Top Level API - Api.Init() and then Sessions (Per-round) API - Session.IsReady() to setup the SDK library and client runtime before you call Session APIs. And please remember to call Top Level API - Api.Shutdown() to teardown the library runtime after you finish using VIVEPORT SDK.
  2. You have to call Start() when a new session of your content starts and call Stop() when this session stops. These two APIs must be pairs.

Implement listener to receive callback of APIs:

  • SessionListener
    • OnSuccess(string pchAppID): callback when IsReady() is successful. Return app ID.
    • OnStartSuccess(string pchAppID, string pchGuid): callback when Start() is successful. Return the app ID, and an unique Guid that represents a session.
    • OnStopSuccess(string pchAppID, string pchGuid): callback when Stop() is successful. Return the app ID, and the Guid that matches the Guid received from the callback of Start().
    • OnFailure(int nCode, string pchMessage): callback when API call fails. Return the error code and message.

Call this function to initialize Session API:

Call this function when a new session of the content starts:

Call this function when this session stops:

Step by step: ViveportSwitch tool

VIVEPORT Arcade Session work flow

_images/Session_SDK_workflow.png

Detailed Example in Unity

using System;
using UnityEngine;
using Viveport;
using Viveport.Arcade;

public class ViveportDemo_ArcadeSession : MonoBehaviour
{
    private int nWidth = 120, nHeight = 40;
    private int nXStart = 10, nYStart = 35;

    static string VIVEPORT_ARCADE_APP_TEST_ID = "app_test_id";
#if UNITY_STANDALONE_WIN
    private Result mListener;
#endif

    // Use this for initialization
    void Start()
    {
        Api.Init(InitStatusHandler, VIVEPORT_ARCADE_APP_TEST_ID);
#if UNITY_STANDALONE_WIN
        Viveport.Core.Logger.Log("Version: " + Api.Version());
        mListener = new Result();
#endif
    }

    // Update is called once per frame
    void Update()
    {

    }

    private void InitStatusHandler(int nResult)
    {
        Viveport.Core.Logger.Log("InitStatusHandler: " + nResult);
        if (nResult != 0)
        {
            Viveport.Core.Logger.Log("Platform setup error ...");

            // Handle error
        }
        else
        {
            Viveport.Core.Logger.Log("Session IsReady");
            Session.IsReady(mListener);
        }
    }

#if UNITY_STANDALONE_WIN
    void OnGUI()
    {
        //******************************************************
        //*        Viveport Arcade Session sample code
        //******************************************************
        if (GUI.Button(new Rect(nXStart, nYStart, nWidth, nHeight), "Session Start"))
        {
            Viveport.Core.Logger.Log("Session Start");
            Session.Start(mListener);
        }

        if (GUI.Button(new Rect(nXStart, nYStart + 1 * nWidth + 10, nWidth, nHeight), "Session Stop"))
        {
            Viveport.Core.Logger.Log("Session Stop");
            Session.Stop(mListener);
        }
    }
    //Declare class which extends Session.SessionListener and implement callback to get the response
    //of APIs. You can make this class for your own customization, for the example here, we return
    //appID, Guid if success. You may store Guid for any purpose
    class Result : Session.SessionListener
    {
        public override void OnSuccess(string pchAppID)
        {
            Viveport.Core.Logger.Log("[Session OnSuccess] pchAppID=" + pchAppID);
        }

        public override void OnStartSuccess(string pchAppID, string pchGuid)
        {
            Viveport.Core.Logger.Log("[Session OnStartSuccess] pchAppID=" + pchAppID + ",pchGuid=" +
                                     pchGuid);
        }

        public override void OnStopSuccess(string pchAppID, string pchGuid)
        {
            Viveport.Core.Logger.Log("[Session OnStopSuccess] pchAppID=" + pchAppID + ",pchGuid=" +
                                     pchGuid);
        }

        public override void OnFailure(int nCode, string pchMessage)
        {
            Viveport.Core.Logger.Log("[Session OnFailed] nCode=" + nCode + ",pchMessage=" + pchMessage);
            //If you get failure callback, you need to do some error handling in your code, for example
            //here, we pause the content. You can also show any warning message to inform user. Please
            //do not start a round if you get failure callback of IsReady() and Start().
            Time.timeScale = 0;
        }
    }
#endif
}

Detailed Example in Unreal

ViveportArcadeSessionDemo.h

#include "Components/ActorComponent.h"
#include "ViveportType.h"
#include "ViveportArcadeSessionType.h"

#include "ViveportArcadeSessionDemo.generated.h"

UCLASS(ClassGroup = (Viveport), meta = (BlueprintSpawnableComponent))
class VIVEPORTSDK_API UViveportArcadeSessionDemo : public UActorComponent
{
    GENERATED_BODY()
public:
    // Called when the game starts
    void BeginPlay() override;

    void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

    /** The VIVEPORT_ID for Session testing*/
    FString VIVEPORT_ID = "3986c32c-64d4-4c5f-ab39-39afeb3fb6bf";
private:
    /** Callback objects */
    class MyViveportApiStatus : public ViveportApiStatus
    {
    protected:
        UViveportArcadeSessionDemo* mDemo;
    public:
        void SetDemoPtr(UViveportArcadeSessionDemo* p) { mDemo = p; }
    };

    class MyViveportArcadeSessionListener : public SessionListener
    {
    protected:
        UViveportArcadeSessionDemo* mDemo;
    public:
        void SetDemoPtr(UViveportArcadeSessionDemo* p) { mDemo = p; }
    };

    class MyInitCallback : public MyViveportApiStatus
    {
    public:
        void OnSuccess(
            ) override;
        void OnFailure(
            int nErrorCode
            ) override;
    };

    MyInitCallback myInitCallback;

    class MyShutdownCallback : public MyViveportApiStatus
    {
    public:
        void OnSuccess(
            ) override;
        void OnFailure(
            int nErrorCode
            ) override;
    };

    MyShutdownCallback myShutdownCallback;

    class MyIsReadyCallback : public MyViveportArcadeSessionListener
    {
    public:
        void OnSuccess(
            const FString& pchAppID
            ) override;
        void OnFailure(
            int nCode,
            const FString& pchMessage
            ) override;
    };

    MyIsReadyCallback myIsReadyCallback;

    class MyStartSessionCallback : public MyViveportArcadeSessionListener
    {
    public:
        void OnStartSuccess(
            const FString& pchAppID,
            const FString& pchGuid
            ) override;
        void OnFailure(
            int nCode,
            const FString& pchMessage
            ) override;
    };

    MyStartSessionCallback myStartSessionCallback;

    class MyStopSessionCallback : public MyViveportArcadeSessionListener
    {
    public:
        void OnStopSuccess(
            const FString& pchAppID,
            const FString& pchGuid
            ) override;
        void OnFailure(
            int nCode,
            const FString& pchMessage
            ) override;
    };

    MyStopSessionCallback myStopSessionCallback;
public:
    ViveportApiStatus* GetInitCallback() { return &myInitCallback; }
    ViveportApiStatus* GetShutdownCallback() { return &myShutdownCallback; }
    SessionListener* GetIsReadyCallback() { return &myIsReadyCallback; }
    SessionListener* GetStartSessionCallback() { return &myStartSessionCallback; }
    SessionListener* GetStopSessionCallback() { return &myStopSessionCallback; }
};

ViveportArcadeSessionDemo.cpp

#include "ViveportSDKPrivatePCH.h"
#include "ViveportArcadeSessionDemo.h"
#include "ViveportApi.h"
#include "ViveportArcadeSession.h"

void UViveportArcadeSessionDemo::BeginPlay()
{
    Super::BeginPlay();

    myInitCallback.SetDemoPtr(this);
    myShutdownCallback.SetDemoPtr(this);
    myIsReadyCallback.SetDemoPtr(this);
    myStartSessionCallback.SetDemoPtr(this);
    myStopSessionCallback.SetDemoPtr(this);

    // Call ViveportApi::Init()
    UViveportApi::Init(&myInitCallback, VIVEPORT_ID);
}

void UViveportArcadeSessionDemo::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    Super::EndPlay(EndPlayReason);

    // Call ViveportApi::Shutdown()
    UViveportApi::Shutdown(&myShutdownCallback);
}

/***************************************************************
*                                   MyInitCallback
***************************************************************/

void UViveportArcadeSessionDemo::MyInitCallback::OnSuccess()
{
    UE_LOG(ViveportSDK, Log, TEXT("[UViveportArcadeSessionDemo][MyInitCallback] Init success."));
    FString fstring("Init success.");
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);

    UViveportArcadeSession::IsReady(mDemo->GetIsReadyCallback());
}

void UViveportArcadeSessionDemo::MyInitCallback::OnFailure(int nErrorCode)
{
    UE_LOG(ViveportSDK, Log, TEXT("[UViveportArcadeSessionDemo][MyInitCallback] Init failure.
                                  Error = %d"), nErrorCode);
    FString fstring = FString::Printf(TEXT("Init failure. Error = %d"), nErrorCode);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);
}

/***************************************************************
*                                   MyShutdownCallback
***************************************************************/

void UViveportArcadeSessionDemo::MyShutdownCallback::OnSuccess()
{
    UE_LOG(ViveportSDK, Log, TEXT("[UViveportArcadeSessionDemo][MyShutdownCallback] Shutdown
                                   success."));
    FString fstring("Shutdown success.");
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);
}

void UViveportArcadeSessionDemo::MyShutdownCallback::OnFailure(int nErrorCode)
{
    UE_LOG(ViveportSDK, Error, TEXT("[UViveportArcadeSessionDemo][MyShutdownCallback] Shutdown
                                    failure. Error = %d"), nErrorCode);
    FString fstring = FString::Printf(TEXT("Shutdown failure. error=%d"), nErrorCode);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);
}

/***************************************************************
*                                   MyIsReadyCallback
***************************************************************/

void UViveportArcadeSessionDemo::MyIsReadyCallback::OnSuccess(const FString& pchAppID)
{
    UE_LOG(ViveportSDK, Log, TEXT("[UViveportArcadeSessionDemo][MyIsReadyCallback] IsReady
                                  success. app ID = %s"), *pchAppID);
    FString fstring = FString::Printf(TEXT("Is ready success, app ID = %s"), *pchAppID);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);

    // start session
    UViveportArcadeSession::Start(mDemo->GetStartSessionCallback());
}

void UViveportArcadeSessionDemo::MyIsReadyCallback::OnFailure(int nCode, const FString&
                                                              pchMessage)
{
    UE_LOG(ViveportSDK, Error, TEXT("[UViveportArcadeSessionDemo][MyIsReadyCallback] IsReady
                                    failure. Code = %d, message = %s"), nCode, *pchMessage);
    FString fstring = FString::Printf(TEXT("IsReady failure. Code = %d, message = %s"), nCode,
                                      *pchMessage);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);
}

/***************************************************************
*                                   MyStartSessionCallback
***************************************************************/

void UViveportArcadeSessionDemo::MyStartSessionCallback::OnStartSuccess(const FString& pchAppID,
                                                                        const FString& pchGuid)
{
    UE_LOG(ViveportSDK, Log, TEXT("[UViveportArcadeSessionDemo][MyStartSessionCallback] start
                                   session success. pchAppID = %s, pchGuid = %s"), *pchAppID,
                                   *pchGuid);
    FString fstring = FString::Printf(TEXT("start session success. pchAppID = %s, pchGuid=%s"),
                                      *pchAppID, *pchGuid);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);

    UViveportArcadeSession::Stop(mDemo->GetStopSessionCallback());
}

void UViveportArcadeSessionDemo::MyStartSessionCallback::OnFailure(int nCode, const FString&
                                                                   pchMessage)
{
    UE_LOG(ViveportSDK, Error, TEXT("[UViveportArcadeSessionDemo][MyStartSessionCallback] start
                                     session failure. Code = %d, message = %s"), nCode,
                                     *pchMessage);
    FString fstring = FString::Printf(TEXT("start session failure. code = %d, message = %s"),
                                      nCode, *pchMessage);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);
}

/***************************************************************
*                                   MyStopSessionCallback
***************************************************************/

void UViveportArcadeSessionDemo::MyStopSessionCallback::OnStopSuccess(const FString& pchAppID,
                                                                      const FString& pchGuid)
{
    UE_LOG(ViveportSDK, Log, TEXT("[UViveportArcadeSessionDemo][MyStopSessionCallback] stop session
                                  success. pchAppID = %s, pchGuid = %s"), *pchAppID, *pchGuid);
    FString fstring = FString::Printf(TEXT("stop session success. pchAppID = %s, pchGuid=%s"),
                                      *pchAppID, *pchGuid);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);

}

void UViveportArcadeSessionDemo::MyStopSessionCallback::OnFailure(int nCode, const FString& pchMessage)
{
    UE_LOG(ViveportSDK, Error, TEXT("[UViveportArcadeSessionDemo][MyStopSessionCallback] stop session
                                    failure. Code = %d, message = %s"), nCode, *pchMessage);
    FString fstring = FString::Printf(TEXT("stop session failure. code = %d, message = %s"), nCode,
                                           *pchMessage);
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::White, fstring);
}

FAQ

When should we send Start() and Stop() API in app?

Take a famous arcade game Street Fighter as example: the game rule is use Best of Three.

  1. A session starts after the player has chosen their character, when game play actually begins e.g. the player starts the first fight. You should call Start() at this moment.
  2. The same session continues during the two or three rounds (win-win / lose-lose / win-lose-win / lose-win-lose)
  3. After the player wins twice or loses twice, the game is over, and this is when the session ends. You should call Stop() at this moment.

Problem in multi-player game

For multi-player game, whether your content is being game server or game client, please make sure every content call Init() and then IsReady() to do initialization when content starts. When a new session of your content starts, call Start(), and call Stop() when this session stops. If you do not follow the guideline, the calculation of sessions will be wrong and it may cause your loss.