Skip to content

PlayFab/PlayFabCSdk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PlayFabCSdk

Cross-Platform C/C++ PlayFab SDK.

This SDK currently supports the following platforms:

  • Windows (Win32) x64
  • GDK (Xbox and Windows)
  • Linux (eg. Ubuntu 22.04 or Windows Subsystem for Linux)
  • iOS
  • macOS
  • Android

For per-platform getting started guides and a complete list of available APIs, check out the online documentation.

Requirements

Win32

iOS / macOS

Android

Project setup

Building with binary release package

Download the most recent release of the SDK from PlayFabCSdk releases.

Integrate PlayFab C SDK into your own project - Visual Studio

The release package contains the required headers, binaries, and a PlayFabServicesSDK.Win32.props file that can imported to your project to automatically add references to them.

You can import the props file manually by editing the .vcxproj files directly or by opening the Property Manager window in Visual Studio, right clicking on the project, and choosing Add Existing Property Sheet. After importing PlayFabServicesSDK.Win32.props, the headers should be available in your include path and references to the PlayFabServices library and its dependecies will be automatically added.

Integrate PlayFab C SDK into your own project - XCode

Add binaries to your game

After getting your binaries by download or building from source you should be able to easily integrate them into your game/app.

Follow these instructions to add them:

  1. In XCode, navigate to your desired target and select it.
  2. Scroll down and in the "Frameworks, Libraries, and Embedded Content" section, click on the "+" sign.
  3. Search for your PlayFabServices / PlayFabCore / HttpClient binaries. (If you downloaded the xcframework file you can also select and it will automatically import whatever library is required independently if you're building for devices or simulator.)
Add Header search paths

Once binaries have been added you'll need to ensure that header search paths are also correctly set up.

  1. Navigate to your project.
  2. Click on "Build Settings" and then search for "Header Search Paths".
  3. Update the property value to include the SDK Headers. Please note that if you are using binaries from the downloaded release package you can simply reference the headers found in the include folder. However, if you are using binaries built from source you'll need to include the following paths:
    PlayFab.C/Source/PlayFabServices/Include/Generated/
    PlayFab.C/Source/PlayFabCore/Include/
    PlayFab.C/Source/PlayFabCore/Include/Generated
    libHttpClient/Include
    

Integrate PlayFab C SDK into your own project - Android Studio

Add Shared Objects and Header files
  1. Using target_include_directories or another equivalent function, add the headers under "Include" from the PlayFab SDK release:
TARGET_INCLUDE_DIRECTORIES(
    ${PROJECT_NAME}
    "Include"
)

If you're building from source, add this list of headers from the PlayFab SDK repository:

    "PlayFab.C/Source/PlayFabServices/Include"
    "PlayFab.C/Source/PlayFabServices/Include/Generated"
    "PlayFab.C/Source/PlayFabCore/Include"
    "PlayFab.C/Source/PlayFabCore/Include/Generated"
    "libHttpClient/Include"
  1. Using target_link_libraries or another equivalent function, link the locations of the .so files to your project.

    For example:

set(PLAYFAB_SERVICES_PATH "[LOCATION OF YOUR FILE]/libPlayFabServices.Android.so")

set(PLAYFAB_CORE_PATH "[LOCATION OF YOUR FILE]/libPlayFabCore.Android.so")

set(LIBHTTPCLIENT_PATH "[LOCATION OF YOUR FILE]/libHttpClient.Android.so")

TARGET_LINK_LIBRARIES(
    [YOUR PROJECT NAME]
    ${PLAYFAB_SERVICES_PATH}
    ${PLAYFAB_CORE_PATH}
    ${LIBHTTPCLIENT_PATH}
)
Add Android Archive files
  1. Create a libs folder within app level Android project directory.

  2. Copy the .aar files into the libs folder.

  3. In app level build.gradle file, the one in the same directory as the libs folder, add these lines to the dependencies section. The second line is required as a dependency for libHttpClient.

implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation 'com.squareup.okhttp3:okhttp:4.9.1'

Cloning source

This SDK depends on some external third-party open source libraries referenced as git submodules in directory /External. Please make sure to use --recurse-submodules command line parameter when cloning this git repo:

git clone --recurse-submodules https://github.com/PlayFab/PlayFabCSdk

or run the following commands to sync the content of submodules if the repo was cloned earlier without the --recurse-submodules parameter:

git submodule update --init --recursive

Building from source for Windows and GDK

After cloning this repository and its submodules, you can build the libraries by opening the solution file PlayFab.C.vs2022.sln. That solution contains the PlayFabServices project, its dependencies, and a test app. After building, the binaries will be in a subdirectory within \Out.

Import Property Sheet (Windows and GDK)

To add a reference to the PlayFabServices projects to your own title, import the \Build\PlayFabServices.import.props file to your project. You can do this manually by editing the .vcxproj files directly or by opening the Property Manager window in Visual Studio, right clicking on the project, and choosing Add Existing Property Sheet. Note that the props file differs from the PlayFabServicesSDK.Win32.props mentioned above - it adds references to the projects instead of the prebuilt binaries.

Building (Windows and GDK)

To add a reference to the PlayFabServices projects to your own title, import the \Build\PlayFabServices.import.props file to your project. You can do this manually by editing the .vcxproj files directly or by opening the Property Manager window in Visual Studio, right clicking on the project, and choosing Add Existing Property Sheet. Note that the props file differs from the PlayFabServicesSDK.Win32.props mentioned above - it adds references to the projects instead of the prebuilt binaries.

PlayFabServicesTestApp

The included test app PlayFabServicesTestApp project will build as is, but some additional setup is required before it will run. The \Test\testTitleData.json file needs to be populated with a valid titleId, developer secret key, and connection string. Additionally, some APIs that are disabled by default need to be enabled via the PlayFab developer portal.

Even without making those changes, the PlayFabServicesTestApp source code serves as a good example of basic PlayFabServices SDK usage.

Building from source for Linux

After cloning this repository and its submodules, you can build the libraries by running

./Build/PlayFabServices.Linux/PlayFabServices_Linux.bash

For more detail on script options see PlayFabServices_Linux

Once built, the shared library can be used by adding this to your project's CMakeLists.txt:

find_package(PlayFabServicesLinux REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC PlayFabServicesLinux)

when running cmake, add this option and adjust the path as needed to tell it where package material can be found:

-D PlayFabServicesLinux_DIR=./Int/CMake/PlayFabServicesLinux

See .\Test\PlayFabServicesTestApp\Linux for example CMake usage.

Building from source for iOS

After cloning this repository and its submodules, you can build the libraries by opening the workspace PlayFab.C.Apple.xcworkspace with XCode, then follow these steps:

  1. Select the scheme you want to build.
  • If you want to build PlayFabServices and PlayFabCore frameworks, select PlayFabServices_iOS/PlayFabServices_._macOS scheme and build. This scheme will generate the frameworks required to use PlayFab SDK:

    • PlayFabCore_[iOS/macOS].framework
    • PlayFabServices_[iOS/macOS].framework
    • HttpClient_[iOS/macOS].framework
  • If you want to run the Test App, select the PlayFabServicesTestApp_._iOS/PlayFabServicesTestApp_macOS scheme, build and run the app.

  1. Select the run destination.
  • For macOS you should be able to run on your own Mac, however, for iOS, you should select a Simulator running iOS 16.2 (or later) or you can run it on a physical devices attached to your Mac. Be aware that libraries built for simulators won't work on real devices and viceversa, so you need to choose the run destination based on where you want to run your app.
  1. Grab the binaries. There are 2 different ways to do it:

    1. Binaries will be placed in XCode default build directory which it's in the DerivedData folder usually located in:

      ~/Library/Developer/Xcode/DerivedData

      In there, you can go to the target folder and navigate to the Build/Products folder to get all the binaries.

    2. Another way to get to the binaries if you want to navigate directly to them:

      1. In the workspace navigation on XCode go to "Products" and expand it.
      2. Right-click on the framework generated and click "Show on Finder".

Building from source for Android

After cloning this repository and its submodules, you can build the libraries from the PlayFab.C/Build/PlayFabServices.Android.Workspace directory by running:

./gradlew assembleFull

This will build the library in two configurations, debug and release, and two Android ABIs, arm64-v8a and x86_64.

If you wish to build separately for a single configuration, ABI, or both, the command can be freely mix and matched for this purpose.

Some examples of altering the command:

This builds for debug arm64-v8a and debug x86_64.

./gradlew assembleFullDebug

This builds for release x86_64.

./gradlew assemblex86_64Release

Init and Logging in

Headers

Include PFServices.h to get access to all included PlayFab functionality:

#include <playfab/services/PFServices.h>

Initialization

PlayFab initialization requires two function calls: PFServicesInitialize and PFServiceConfigCreateHandle. The result of this initialization is a PFServiceConfigHandle. You provide this handle to a subsequent login call, directing the call to the correct title in the PlayFab backend.

    HRESULT hr = PFServicesInitialize(nullptr); // Add your own error handling when FAILED(hr) == true

    PFServiceConfigHandle serviceConfigHandle{ nullptr };

    hr = PFServiceConfigCreateHandle(
            "https://ABCDEF.playfabapi.com",    // PlayFab API endpoint - obtained in the Game Manager
            "ABCDEF",                           // PlayFab Title id - obtained in the Game Manager
            &serviceConfigHandle);

Logging in

Once you have a PFServiceConfigHandle, you can use it to make a player login call. In the SDK, use a PFAuthenticationLoginWith*Async method like PFAuthenticationLoginWithCustomIDAsync. This function allows you to log in a player to PlayFab using a custom string, which is useful during development and testing.

After making a login call, you can check the status of the call with XAsyncGetStatus. The status starts as E_PENDING and changes to S_OK after the call completes successfully. If the call fails for some reason, the status reflects that failure. Error handling on all PlayFab Services calls works this way.

Along with an S_OK result, you get back a PFEntityHandle. You use this handle to make subsequent PlayFab calls as the logged in player. It includes any material required to authenticate with the PlayFab service as that player.

    PFAuthenticationLoginWithCustomIDRequest request{};
    request.createAccount = true;
    request.customId = "player1";

    XAsyncBlock async{};
    HRESULT hr = PFAuthenticationLoginWithCustomIDAsync(serviceConfigHandle, &request, &async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

    std::vector<char> loginResultBuffer;
    PFAuthenticationLoginResult const* loginResult;
    size_t bufferSize;
    hr = PFAuthenticationLoginWithCustomIDGetResultSize(&async, &bufferSize);
    loginResultBuffer.resize(bufferSize);

    PFEntityHandle entityHandle{ nullptr };
    hr = PFAuthenticationLoginWithCustomIDGetResult(&async, &entityHandle, loginResultBuffer.size(), loginResultBuffer.data(), &loginResult, nullptr);

Service Calls

After logging the player in, you can now make calls to the PlayFab backend. Here's an example of a call to get files stored in PlayFab for the current player.

Getting the EntityKey

One thing that can be useful for some calls to PlayFab is knowing the PFEntityKey of the player. Once you have a PFEntityToken, you can retrieve a PFEntityKey with PFEntityGetEntityKey.

    PFEntityKey const* pEntityKey{};
    std::vector<char> entityKeyBuffer;
    size_t size{};
    HRESULT hr = PFEntityGetEntityKeySize(entityHandle, &size); // Add your own error handling when FAILED(hr) == true

    entityKeyBuffer.resize(size);
    hr = PFEntityGetEntityKey(entityHandle, entityKeyBuffer.size(), entityKeyBuffer.data(), &pEntityKey, nullptr);

Calling GetFiles

All PlayFab calls follow a similar pattern of preparing the request object, making the call (using the PFEntityHandle from login), creating an object to receive the response, and then calling a GetResult function to fill the newly created container.

    XAsyncBlock async{};
    PFDataGetFilesRequest requestFiles{};
    requestFiles.entity = pEntityKey;

    HRESULT hr = PFDataGetFilesAsync(entityHandle, &requestFiles, &async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

    size_t resultSize;
    hr = PFDataGetFilesGetResultSize(&async, &resultSize);

    std::vector<char> getFilesResultBuffer(resultSize);
    PFDataGetFilesResponse* getFilesResponseResult{ nullptr };
    hr = PFDataGetFilesGetResult(&async, getFilesResultBuffer.size(), getFilesResultBuffer.data(), &getFilesResponseResult, nullptr);

Clean up

When your game is ready to shut down or you need to clean up PlayFab for some other reason, ensure you close all open handles and call PFServicesUninitializeAsync.

    PFEntityCloseHandle(entityHandle);
    entityHandle = nullptr;

    PFServiceConfigCloseHandle(serviceConfigHandle);
    serviceConfigHandle = nullptr;

    XAsyncBlock async{};
    HRESULT hr = PFServicesUninitializeAsync(&async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

Async API pattern

The PlayFab Services SDK follows an Asynchronous Programming Model. This programming model involves the use of Tasks and Task Queues provided by the XAsync library. While it does introduce some complexity, it also brings a high degree of control over asynchronous operations.

This example shows how to make an asynchronous call to PFDataGetFilesAsync.

    auto async = std::make_unique<XAsyncBlock>();
    async->callback = [](XAsyncBlock* async)
    {
        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock

        size_t resultSize;
        HRESULT hr = PFDataGetFilesGetResultSize(async, &resultSize);
        if (SUCCEEDED(hr))
        {
            std::vector<char> getFilesResultBuffer(resultSize);
            PFDataGetFilesResponse* getFilesResponseResult{ nullptr };
            PFDataGetFilesGetResult(async, getFilesResultBuffer.size(), getFilesResultBuffer.data(), &getFilesResponseResult, nullptr);
        }
    };

    PFDataGetFilesRequest requestFiles{};
    requestFiles.entity = m_pEntityKey;
    HRESULT hr = PFDataGetFilesAsync(m_entityHandle, &requestFiles, async.get());
    if (SUCCEEDED(hr))
    {
        async.release(); // at this point, the callback will be called so release the unique ptr
    }

Error handling

Completed XAsync operations return HTTP status codes. An error status code manifests as a failure HRESULT such as HTTP_E_STATUS_NOT_FOUND when calling XAsyncGetStatus() or one of the PF*Get() APIs.

To see detailed error messages returned by the service see the next section on debugging. These detailed error messages can be useful during development to better understand how the PlayFab service reacts to requests from the client.

Debugging

The easiest way to see the results and debug any calls in the PlayFab Services SDK is to enable Debug Tracing. Enabling debug tracing allows you to both see the results in the debugger output window and hook the results into your game's own logs.

Reference

API reference documentation