Player Data Storage Interface

Interface to handle cloud-based data management

The Player Data Storage Interface enables developers using Epic Online Services (EOS) to save encrypted, user-specific, game-specific data to cloud servers. Data that you store through this interface is accessible to the user on any device where they can log in. The Player Data Storage Interface supports any file format; typical use cases would include saved games and replay data.

To access the Player Data Storage Interface, acquire an EOS_HPlayerDataStorage handle through the Platform Interface function, EOS_Platform_GetPlayerDataStorageInterface. All Player Data Storage Interface functions require this handle as their first parameter. You must ensure that the EOS_HPlatform handle is ticking for appropriate callbacks to trigger when requests are completed.

To use this interface, you must initialize the EOS Platform with the following extra parameters:

  • const char* EncryptionKey: This 64-character hexadecimal string builds a 256-bit key that EOS uses to encrypt user data. Epic's backend servers do not store this key. If there is no key, calls to file-management functions from the Player Data Storage Interface will result in failure and will return the EOS_PlayerDataStorage_EncryptionKeyNotSet error code.

  • const char* CacheDirectory: This is the full path to the local directory that the interface will use for temporary storage during data file transfers. This could be any location, with the system's temporary directory or the game's data directory being common choices. If the directory you specify does not exist, EOS will attempt to create it. You can use the same directory for multiple users and products, and EOS will ensure that they do not collide. If there are issues with the directory, calls to file-management functions will result in failure and will return EOS_CacheDirectoryMissing or EOS_CacheDirectoryInvalid error codes. Please refer to the EOS Platform documentation for platform-specific limitations on what folders can be used.

File Management

File Name Format

File names in EOS take the following form: Directory0/Directory1/DirectoryN/Filename.Extension

The "Directory" and "Extension" portions are optional. The "/" character must appear after each directory name, but cannot appear anywhere else, including as the first or last character. File names may use the following characters:

  • Any alphanumeric ASCII character

  • !

  • -

  • _

  • +

  • .

  • *

  • '

  • (

  • )

File names may not exceed EOS_PLAYERDATASTORAGE_FILENAME_MAX_LENGTH_BYTES (64) characters.

Querying Files

You can get information about one or all files stored on the cloud by querying EOS. Either query type will return metadata about the file or files it discovers, including the file's name, data size (in bytes, unencrypted), and MD5 hash. You can then cache a copy of this information before accessing or modifying files. Note that since files are stored in an encrypted form on the backend, some metadata (such as file size and hash) is provided for the encrypted file. The metadata won't exactly match values that correspond to the file you pass to the API.

Be sure to copy any information you may need from the cache during your query's callback function. This data's lifetime is not guaranteed to last beyond the duration of the callback function. This is especially important when running multiple queries, as each successful query can alter the contents of the cache.

Querying All Files

To retrieve information about all files, call EOS_PlayerDataStorage_QueryFileList with an EOS_PlayerDataStorage_QueryFileListOptions data structure, initialized as follows:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_QUERYFILELISTOPTIONS_API_LATEST

LocalUserId

The EOS_ProductUserId of the local user who is requesting file data

Upon completion, EOS will run your callback function (of type EOS_PlayerDataStorage_OnQueryFileListCompleteCallback) with an EOS_PlayerDataStorage_QueryFileListCallbackInfo data structure. If the call succeeded, the data structure contains the number of files found, and the information about those files is available in the EOS cache.

Querying a Single File

If you only need information about a single file, and you know that file's name, you can call EOS_PlayerDataStorage_QueryFile function, passing in an EOS_PlayerDataStorage_QueryFileOptions structure initialized as follows:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_QUERYFILEOPTIONS_API_LATEST

LocalUserId

The EOS_ProductUserId of the local user who is requesting file data

Filename

The name of the file you are querying

When the operation completes, EOS will run your callback (of type EOS_PlayerDataStorage_OnQueryFileCompleteCallback) with an EOS_PlayerDataStorage_QueryFileCallbackInfo structure. If the call succeeded, EOS now has data about your file in the cache.

Examining Cached File Information

Once EOS has retrieved and cached information about one or more files, you can retrieve information on a specific file by calling EOS_PlayerDataStorage_CopyFileMetadataByFilename with the name of the file, or by calling EOS_PlayerDataStorage_CopyFileMetadataAtIndex with the file's zero-based index within the cache. If you need to know how many files are in the cache, you can call EOS_PlayerDataStorage_GetFileMetadataCount. Once you no longer need your copy of this information, release the memory it was using by calling EOS_PlayerDataStorage_FileMetadata_Release.

After querying EOS for information about a single file, EOS_PlayerDataStorage_GetFileMetadataCount may reveal that the cache holds multiple files. This can happen when results from previous queries remain in the cache. In these cases, the best practice is to check that the ResultCode within your EOS_PlayerDataStorage_QueryFileCallbackInfo is EOS_Success, and to call EOS_PlayerDataStorage_CopyFileMetadataByFilename to access its information.

File metadata structure appears as the following:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_FILEMETADATA_API_LATEST

FileSizeBytes

The total size of the file in bytes (in encrypted form, can be slightly more than expected)

MD5Hash

The MD5 Hash of the entire file, in hex digits (hash of encrypted file)

Filename

The file's name

Accessing and Modifying Files

EOS supports reading, writing, and deleting files from the cloud asynchronously. Reading and writing are streaming operations, and EOS provides handles that the game can use to check a stream's progress, or throttle or interrupt it.

Reading a File

To read a file from the cloud (or your local cache) with a known name, call EOS_PlayerDataStorage_ReadFile. You will need to pass in an EOS_PlayerDataStorage_ReadFileOptions initialized as follows:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_READFILEOPTIONS_API_LATEST

LocalUserId

The Account ID of the local user who is reading the requested file

Filename

The name of the file to read

ReadChunkLengthBytes

The maximum amount of data to read in a single EOS_PlayerDataStorage_OnReadFileDataCallback call

ReadFileDataCallback

Callback function that handles data as it comes in, and can stop the transfer early

FileTransferProgressCallback

Optional callback function to inform you of transfer progress; will be called at least once if set

This function returns an EOS_HPlayerDataStorageFileTransferRequest handle that you can use to check the progress of the transfer, get the name of the file, or cancel the transfer. At any time during the transfer, call EOS_PlayerDataStorageFileTransferRequest_GetFileRequestState to poll its current state, EOS_PlayerDataStorageFileTransferRequest_GetFilename to check the name of the file being transferred, or EOS_PlayerDataStorageFileTransferRequest_CancelRequest to cancel it (without generating an error). If you prefer to receive updates from EOS rather than polling the transfer directly, provide a valid EOS_PlayerDataStorage_OnFileTransferProgressCallback function when initiating the transfer (as the FileTransferProgressCallback parameter), and EOS will call it (with an EOS_PlayerDataStorage_FileTransferProgressCallbackInfo parameter) periodically to inform you of the progress of the file transfer. If you choose this route, you are guaranteed to receive at least one call to your callback function. Using the callback function does not preclude using the handle, though they serve very similar purposes and most use cases will not require both.

When a chunk of the file comes through, your ReadFileDataCallback (of type EOS_PlayerDataStorage_OnReadFileDataCallback) will run with a parameter of type EOS_PlayerDataStorage_ReadFileDataCallbackInfo. This structure includes a chunk of the actual data from the file, as well as a variable indicating whether or not this is the last chunk. It also has an enumerated return type, EOS_PlayerDataStorage_EReadResult, which you can use to instruct EOS to continue the transfer, end it due to an error, or cancel it without reporting an error.

ReadFileDataCallback will only be called from the main SDK thread (the one you are using to tick the SDK) and only once per tick. This is why it is important to set the right value for ReadChunkLengthBytes. Setting the chunk size to a value that is too small will degrade reading performance for the user. We recommend using a multiple of 4096, as this normally corresponds to your system's memory page size. You can estimate the maximum reading speed by multiplying ReadChunkLengthBytes by the SDK tick frequency. E.g. 4096 * 30 will give you up to 120 kilobytes per second. Using a chunk size that is too large, on the other hand, will make the SDK allocate more memory internally. In order to leave a reasonable footprint, you should pick a value that suits your needs best.

Once the file transfer has completed, EOS will run your EOS_PlayerDataStorage_OnReadFileCompleteCallback callback function with an EOS_PlayerDataStorage_ReadFileCallbackInfo parameter. This parameter indicates success or failure, and includes the name of the file.

EOS may cache files locally to speed up future read operations. These files will be encrypted with the key you provided during EOS Platform initialization. Data chunks sent to your ReadFileDataCallback function will not be encrypted.

The following timeline diagram shows a hypothetical read operation in action:

PDSChart.png

When downloading multiple files in succession, you can improve performance by querying the file list first, caching the metadata, then performing downloads. This avoids having to perform multiple queries and wait for the results between file downloads.

Writing a File

To write a file with a known name, call EOS_PlayerDataStorage_WriteFile. You will need to pass in an EOS_PlayerDataStorage_WriteFileOptions initialized as follows:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_WRITEFILEOPTIONS_API_LATEST

LocalUserId

The Account ID of the local user who is writing the file to the cloud

Filename

The name of the file to write

ChunkLengthBytes

The maximum amount of data to write to the file in a single tick

WriteFileDataCallback

Callback function that provides chunks of data to EOS

FileTransferProgressCallback

Optional callback function (type EOS_PlayerDataStorage_OnFileTransferProgressCallback) to inform you of transfer progress; will be called at least once if set

This function returns an EOS_HPlayerDataStorageFileTransferRequest handle that you can use to check the progress of the transfer, get the name of the file, or cancel the transfer. At any time during the transfer, call EOS_PlayerDataStorageFileTransferRequest_GetFileRequestState to poll its current state, EOS_PlayerDataStorageFileTransferRequest_GetFilename to check the name of the file being transferred, or EOS_PlayerDataStorageFileTransferRequest_CancelRequest to cancel it (without generating an error). If you prefer to receive updates from EOS rather than polling the transfer directly, provide a valid EOS_PlayerDataStorage_OnFileTransferProgressCallback function when initiating the transfer (as the FileTransferProgressCallback parameter), and EOS will call it (with an EOS_PlayerDataStorage_FileTransferProgressCallbackInfo parameter) periodically inform you of the progress of the file transfer. If you choose this route, you are guaranteed to receive at least one call to your callback function. Using the callback function does not preclude using the handle, though they serve very similar purposes and most use cases will not require both.

When EOS wants to send the next chunk of the file to the cloud, your WriteFileDataCallback (of type EOS_PlayerDataStorage_OnWriteFileDataCallback) will run with a parameter of type EOS_PlayerDataStorage_WriteFileDataCallbackInfo, as well as a void pointer to a buffer for the outgoing data and a uint32_t pointer to indicate the size of that data. The EOS_PlayerDataStorage_WriteFileDataCallbackInfo has a variable called DataBufferLengthBytes that indicates the maximum number of bytes that you can put into the buffer. This callback function has an enumerated return type, EOS_PlayerDataStorage_EWriteResult, which you can use to instruct EOS to continue the transfer, end it due to successful completion, end it due to an error, or cancel it without reporting an error.

WriteFileDataCallback will only be called from the main SDK thread (the one you are using to tick the SDK) and only once per tick. This is why it is important to set the right value for ChunkLengthBytes. Setting the chunk size to a value that is too small will degrade writing performance for the user. We recommend using a multiple of 4096, as this normally corresponds to your system's memory page size. You can estimate the maximum writing speed by multiplying ChunkLengthBytes by the SDK tick frequency. E.g. 4096 * 30 will give you up to 120 kilobytes per second. Using a chunk size that is too large, on the other hand, will make the SDK allocate more memory internally. In order to leave a reasonable footprint, you should pick a value that suits your needs best.

Once the file transfer has completed, EOS will run your EOS_PlayerDataStorage_OnWriteFileCompleteCallback callback function with an EOS_PlayerDataStorage_WriteFileCallbackInfo parameter. This parameter indicates success or failure and includes the name of the file. To avoid data loss, ensure that this callback runs before before letting the user quit the game or shut down the console.

Copying a File

If you wish to make a copy of a file, you can do so without manually reading and writing the file's full data content. Call EOS_PlayerDataStorage_DuplicateFile with an EOS_PlayerDataStorage_DuplicateFileOptions containing the following values:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_DUPLICATEFILEOPTIONS_API_LATEST

LocalUserId

The Account ID of the local user who authorizes the operation; must be the original file's owner

SourceFilename

The name of the existing file to copy

DestinationFilename

The desired name of the duplicate file

Upon completion, EOS will run your EOS_PlayerDataStorage_OnDuplicateFileCompleteCallback function with an EOS_PlayerDataStorage_DuplicateFileCallbackInfo parameter. File duplication will fail if the user does not own the original file, or if the user is out of storage space. If DestinationFilename identifies a file that already exists, that file will be replaced with the duplicate.

Deleting a File

You can delete a file by calling EOS_PlayerDataStorage_DeleteFileOptions with an EOS_PlayerDataStorage_DeleteFileOptions initialized as follows:

Property

Value

ApiVersion

EOS_PLAYERDATASTORAGE_DELETEFILEOPTIONS_API_LATEST

LocalUserId

The Account ID of the local user who authorizes deletion of the file; must be the file's owner

Filename

The name of the file to delete

Upon completion, EOS will run your callback (of type EOS_PlayerDataStorage_OnDeleteFileCompleteCallback) and pass a parameter of type EOS_PlayerDataStorage_DeleteFileCallbackInfo to it. File deletion operations can fail if the user does not own the file.

Data Caching and Encryption

The Player Data Storage Interface caches file data and metadata in the CacheDirectory folder on the client system. Whenever possible, EOS will use this data instead of streaming from the cloud, for both read and write operations, using MD5 checksum testing to prevent data corruption and to determine when the locally cached file is identical to the version on the cloud, in which case read and write operations can complete in a single callback cycle. Any successful read or write operation updates the cache, while deletion clears the cached file and removes its metadata. EOS does not clear the cache upon shutdown, enabling reuse of cached files in future sessions.

Player Data Storage files are always stored with encryption, using the key you provide during EOS Platform initialization. The encryption key itself is not stored on the cloud, preventing both Epic Games and malicious third parties from using the key to access clients' data. Encryption keys are automatically modified for each user, so different users cannot decrypt each other's data.

Usage Limitations

Storage space is limited on both a per-file and per-user basis, though the exact values are not fixed at this time. Users also have a limit to the rate at which they can transfer data, including uploads and downloads. There is also a limit on the number of files. In the event that a user attempts to upload past either storage space limit, EOS will cause the upload operation to fail with an error. Transferring too much data at once will not cause an error, but EOS will suspend transfers to that user temporarily. While in this state, users can still retrieve metadata and delete files.

PlayerDataStorage vs EGS Cloud Saves

Epic offers two different cloud save services: Launcher Cloud Saves and EOS Player Data Storage. The former is the most broadly used, and can be set up as part of your game configuration in the Epic Games Store. There are some differences between the services however, which would influence which service to use.

  1. Launcher Cloud Saves are tied to games within the Epic Games Launcher. So if the player was able to launch the game outside the Launcher, the game would only have access to the local version of the save data.

  2. Cloud Saves from the Launcher are handled entirely on the Epic side once configured

  3. EOS Player Data Storage requires the player to be online, and is driven entirely game-side using EOS APIs. This allows for data to be shared across platforms, unlike Launcher Cloud Saves.