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 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 toEOS_Platform_GetPlayerDataStorageInterface
return a null reference. If the key is not the correct length or format, file-management functions from the Player Data Storage Interface will result in failure and return theEOS_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 returnEOS_CacheDirectoryMissing
orEOS_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 |
LastModifiedTime | Date and time when the file was saved last time. Timestamp is in the POSIX/Unix format (Epoch time). |
UnencryptedDataSizeBytes | The total size of the data (payload) in bytes (in its unencrypted original form). |
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:
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 runs your EOS_PlayerDataStorage_OnDuplicateFileCompleteCallback
function with an EOS_PlayerDataStorage_DuplicateFileCallbackInfo
parameter. File duplication fails in the following situtations:
- The original file doesn't exist.
- The user does not own the original file.
- The user is out of storage space.
If DestinationFilename
identifies a file that already exists, that file is 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, so we can't use the key to access your data.
File Decryption Tool
You can the File Decryption Tool to create new files or decrypt files loaded to Title Storage or Player Data Storage easily and conveniently.
Usage Limitations
The Player Data Storage Interface enables developers using 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 include saved games and replay data.
The service applies limits to both storage amounts and usage rates. Throttling enforces usage rate limitations, and the service can delete files to enforce storage space limitations. For general information about throttling, usage quotas, and best practices, see Service Usage Limitations.
Usage Type | Limitation |
---|---|
Read or write | 1000 requests per minute |
Maximum individual file size (see note below) | 200 MB |
Auto-delete file size | 400 MB |
Total storage space per user | 400 MB |
Maximum files per user | 1000 |
If a user tries to upload a file that exceeds either storage space limit, the EOS_PlayerDataStorage_WriteFile
call fails, and returns EOS_Result_PlayerDataStorageFileSizeTooLarge
. When the user's storage is full, additional calls to EOS_PlayerDataStorage_WriteFile
fail, and return EOS_Result_PlayerDataStorageUserThrottled
, which indicates that the user's storage is throttled. The user's storage remains in a throttled state until enough files are removed to bring the storage usage under the limit. Files that exceed the auto-delete file size are deleted following the upload.
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.
- 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.
- Cloud Saves from the Launcher are handled entirely on the Epic side once configured
- 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.