Skip to content

World Persistence (PWI)

Teacup edited this page Sep 28, 2023 · 20 revisions

PWI: VRCX Persistent World Interface

This feature aims to give content creators the ability to store user-machine-specific string data in a local database, thereby facilitating a level of data persistence within VRChat worlds not easily possible otherwise.

I'm not a developer! How do I use this?

To make use of this system as a user, follow these steps:

  • Make sure you have "Allow Untrusted URLs" enabled in your "Comfort & Safety" VRChat Settings.
  • If you have Logging disabled, you will need to re-enable it. If you don't know what this means, it probably doesn't apply.
  • Make sure that VRCX is open when you join a world supporting PWI
    • If you close/re-open VRCX while the world is using PWI, there's a good chance the world will break or not work as expected.

If you're using the standalone quest client, this feature won't work for you.

WARNING - Developers

https://github.com/vrcx-team/VRCX/issues/567

Overview

Without an easy, reliable way for VRChat worlds to maintain persistent data or save states, it is yet another way creators are limited when it comes to creating content in VRC. PWI tries to bridge this gap by providing a system to store arbitrary string data on a local database for each user.

Limitations

  • Users must have VRCX installed and VRChat logging enabled(enabled by default) for the API to function.
  • Users must enable "Allow Untrusted URLs" to facilitate world-VRCX communication, as loopback URLs like 127.0.0.1 aren't whitelisted.
  • Due to reliance on log files for data retrieval from worlds, this system isn't available to quest users.

Operation

VRCX operates a local webserver listening on port 22500 on 127.0.0.1. This server is your interface for retrieving data from the local database using VRChat's String Loading. However, due to limitations like the 5 second-per-request limit on string loading and static URL requirements in Udon/UdonSharp, other functions aren't feasible.

The data is stored as key-value pairs in the database with each world having a unique 'pool' of these pairs accessible only to that world.

Usage: Overview

  1. Initialize a valid connection to VRCX. You can do this by either explicity calling the /vrcx/data/init endpoint, or just using any of the data request endpoints like /vrcx/data/getall and they will initialize the current world automatically. This will provide a connection key in the response, necessary for storing new data. You can make this and the following requests with Udon String Loading

  2. Retrieve data using the /vrcx/data/getx endpoints to request data from the database. You can define the URLs needed for the keys you want to retrieve at compile time and request them afterwards. You don't need a connection key for this.

Example request: http://127.0.0.1:22500/vrcx/data/get?key=test

  1. Store data in the local database by logging data to VRChat's log file, adhering to the requestType's format. Not following the format or not providing a valid connection key will result in the data not being stored. Test your requests! Use VRCJson for parsing and serializing JSON.

Example request: [VRCX-World] {"requestType": "store", "connectionKey": "test-connection-key", "key": "test", "value": "testvalue"}

If your request is invalid or otherwise malformed, the request will fail and your data will not be stored. If you suspect this is happening, you can look at the VRCX.log file or use the /vrcx/data/lasterror endpoint to see the last store error, if any.

Each individual world has a total data cap of 10MB shared across all their data entries. If the world hits this cap, all subsequent storage requests will fail.

PWI Manager Prefab

PWI Manager is a simple but fully-featured implementation of this API that can be dropped into a project and used as-is.

https://github.com/GroovyTeacup/PWIManager

A world running this prefab and its example script can be found here: https://vrchat.com/home/world/wrld_ddbdbb3a-082b-4b23-bf51-a9fd391bbc55

Log Request Types

The following request types are various ways that worlds can log in order to perform certain operations.

store

The store requestType stores a string in the world database under a given key with a value.

If value is null or empty, your request will fail. Use the delete requestType to delete data.

JSON Format

  • requestType: (string) The type of request
  • connectionKey: (string) The connection key for the current world.
  • key: (string) The key to store value under in the database. Max length 255
  • value: (string) Arbitrary string data.

Example Log Line: [VRCX-World] {"requestType": "store", "connectionKey": "test-connection-key", "key": "test", "value": "testvalue"}

delete

The delete requestType deletes a given key in the world database.

JSON Format

  • requestType: (string) The type of request
  • connectionKey: (string) The connection key for the current world
  • key: (string) The key to delete

Example Log Line: [VRCX-World] {"requestType": "delete", "connectionKey": "test-connection-key", "key": "test"}

delete-all

The delete-all requestType deletes all data in the database under the current world.

JSON Format

  • requestType: (string) The type of request
  • connectionKey: (string) The connection key for the current world.

Example Log Line: [VRCX-World] {"requestType": "delete-all", "connectionKey": "test-connection-key"}

set-setting

The set-setting requestType sets a given setting key on a world to value. Currently only supports changing externalReads

JSON Format

  • requestType: (string) The type of request
  • connectionKey: (string) The connection key for the current world.
  • key: (string) The key of the setting to set
  • value: (string) What to set the setting to. May be parsed differently depending on setting.

Example Log Line: [VRCX-World] {"requestType": "set-setting", "connectionKey": "test-connection-key", "key": "externalReads", "value": "true"

Valid World Settings:

externalReads - Setting this to true will allow other worlds to read from your data pool, given that they provide your world's ID in a data request. If false, which it is by default, other worlds will not be able to access your world's data entries.

Endpoints

The following URLs are the various endpoints for worlds to communicate with VRCX through the String Loading methods.

/vrcx/status

Description: This endpoint just returns a blank '200 OK' response when called. You can use it to check if VRCX is running and initialized on the user's machine.

Usage: http://127.0.0.1:22500/vrcx/status

/vrcx/data/init

Description: Initializes a connection to PWI.

URL: /vrcx/data/init

Parameters:

  • debug: (boolean) If true, the current world ID will be set to wrld_12345 and the connection key will be set and returned as 12345. This is useful for testing your implementation/requests without having to be in a world. You can request this and the other endpoints from your browser.

Response: JSON object with the following properties:

  • ok: (boolean) Indicates whether the request was successful.
  • connectionKey: (string) The connection key for the current world. Null if request failed. (Yes this is a duplicate)
  • data: (string) The connection key for the current world. Null if request failed.
  • error: (string) Contains an error message if the request was not successful. Null otherwise.

Status Codes:

  • 200 OK: The request was successful.
  • 500 Internal Server Error: VRCX failed to get the current world id for some reason.
  • 503 Service Unavailable: The VRCX world data service is not yet initialized or is currently loading.

/vrcx/data/get

Description: Retrieves a single value from the local database.

URL: /vrcx/data/get

Example Request: http://127.0.0.1:22500/vrcx/data/get?key=test

Parameters:

  • key: (string) The key to retrieve the value of.
  • world: (string) (Optional) A world ID to retrieve the given key from. The world in question must allow external reads otherwise the request will return null. If the world in question doesn't exist in the user's DB, it will also return null.

Response: JSON object with the following properties:

  • ok: (boolean) Indicates whether the request was successful.
  • connectionKey: (string) The connection key for the current world.
  • data: (string) The value of the key in the local database. Null if request failed.
  • error: (string) Contains an error message if the request was not successful. Null otherwise.

Status Codes:

  • 200 OK: The request was successful.
  • 400 Bad Request: The request was missing the key parameter.
  • 404 Not Found: The key was not found in the local database.
  • 503 Service Unavailable: The VRCX world data service is not yet initialized or is currently loading.

/vrcx/data/getbulk

Description: Retrieves multiple values from the local database.

URL: /vrcx/data/getbulk

Example Request: http://127.0.0.1:22500/vrcx/data/getbulk?keys=test,test2

Parameters:

  • keys: (string) A comma-separated list of keys to retrieve the values of.
  • world: (string) (Optional) A world ID to retrieve the given key from. The world in question must allow external reads otherwise the request will return null. If the world in question doesn't exist in the user's DB, it will also return null.

Response: JSON object with the following properties:

  • ok: (boolean) Indicates whether the request was successful.
  • connectionKey: (string) The connection key for the current world.
  • data: (object) An object containing the values of the keys in the local database in a key:value format. Null if request failed.
  • error: (string) Contains an error message if the request was not successful. Null otherwise.

/vrcx/data/getall

Description: Retrieves all values from the local database for your world. (This is limited to getting, at most, 10000 keys)

URL: /vrcx/data/getall

Example Request: http://127.0.0.1:22500/vrcx/data/getall

Parameters:

  • world: (string) (Optional) A world ID to retrieve the given key from. The world in question must allow external reads otherwise the request will return null. If the world in question doesn't exist in the user's DB, it will also return null.

Response: JSON object with the following properties:

  • ok: (boolean) Indicates whether the request was successful.
  • connectionKey: (string) The connection key for the current world.
  • data: (object) An object containing the values of the keys in the local database in a key:value format. Null if request failed.
  • error: (string) Contains an error message if the request was not successful. Null otherwise.