Module ro_py.gamepersistence

This file houses functions used for tampering with Roblox Datastores

Expand source code
"""

This file houses functions used for tampering with Roblox Datastores

"""

from urllib.parse import quote
from math import floor
import re

from ro_py.utilities.url import url
endpoint = url("gamepersistence")


class DataStore:
    """
    Represents the in-game datastore system for storing data for games (https://gamepersistence.roblox.com).
    This is only available for authenticated clients, and games that they own.

    Parameters
    ----------
    requests : ro_py.utilities.requests.Requests
        Requests object to use for API requests.
    place_id : int
        PlaceId to modify the DataStores for, 
        if the currently authenticated user doesn't have sufficient permissions, 
        it will raise a NotAuthorizedToModifyPlaceDataStores exception
    name : str
        The name of the DataStore, 
        as in the Second Parameter of 
        `std::shared_ptr<RBX::Instance> DataStoreService::getDataStore(const DataStoreService* this, std::string name, std::string scope = "global")`
    scope : str, optional
        The scope of the DataStore,
        as on the Second Parameter of
         `std::shared_ptr<RBX::Instance> DataStoreService::getDataStore(const DataStoreService* this, std::string name, std::string scope = "global")`
    legacy : bool, optional
        Describes whether or not this will use the legacy endpoints, 
        over the new v1 endpoints (Does not apply to getSortedValues)
    legacy_naming_scheme : bool, optional
        Describes whether or not this will use legacy names for data stores, if true, the qkeys[idx].scope will match the current scope (global by default), 
        there will be no qkeys[idx].target (normally the key that is passed into each method), 
        and the qkeys[idx].key will match the key passed into each method.
    """

    def __init__(self, requests, place_id, name, scope, legacy=True, legacy_naming_scheme=False):
        self.requests = requests
        self.place_id = place_id
        self.legacy = legacy
        self.legacy_naming_scheme = legacy_naming_scheme
        self.name = name
        self.scope = scope if scope is not None else "global"

    async def get(self, key):
        """
        Represents a get request to a data store,
        using legacy works the same

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        
        Returns
        -------
        typing.Any
        """
        if self.legacy:
            data = f"qkeys[0].scope={quote(self.scope)}&qkeys[0].target=&qkeys[0].key={quote(key)}" if self.legacy_naming_scheme == True else f"qkeys[0].scope={quote(self.scope)}&qkeys[0].target={quote(key)}&qkeys[0].key={quote(self.name)}"
            r = await self.requests.post(
                url=endpoint + f"persistence/getV2?placeId={str(self.place_id)}&type=standard&scope={quote(self.scope)}",
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': 'application/x-www-form-urlencoded'
                }, data=data)
            if len(r.json()['data']) == 0:
                return None
            else:
                return r.json()['data'][0]['Value']
        else:
            url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.get(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id)
                })
            if r.status_code == 204:
                return None
            else:
                return r.text

    async def set(self, key, value):
        """
        Represents a set request to a data store,
        using legacy works the same

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        value
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        
        Returns
        -------
        typing.Any
        """
        if self.legacy:
            data = f"value={quote(str(value))}"
            url = endpoint + f"persistence/set?placeId={self.place_id}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&valueLength={str(len(str(value)))}" if self.legacy_naming_scheme == True else endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&valueLength={str(len(str(value)))}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': 'application/x-www-form-urlencoded'
                }, data=data)
            if len(r.json()['data']) == 0:
                return None
            else:
                return r.json()['data']
        else:
            url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': '*/*',
                    'Content-Length': str(len(str(value)))
                }, data=quote(str(value)))
            if r.status_code == 200:
                return value

    async def set_if_value(self, key, value, expected_value):
        """
        Represents a conditional set request to a data store,
        only supports legacy

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        value
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        expected_value
            The expected_value for that key, if you know the key doesn't exist, then set this as None

        Returns
        -------
        typing.Any
        """
        data = f"value={quote(str(value))}&expectedValue={quote(str(expected_value)) if expected_value is not None else ''}"
        url = endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&valueLength={str(len(str(value)))}&expectedValueLength={str(len(str(expected_value))) if expected_value is not None else str(0)}" if self.legacy_naming_scheme == True else endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&valueLength={str(len(str(value)))}&expectedValueLength={str(len(str(expected_value))) if expected_value is not None else str(0)}"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        try:
            if r.json()['data'] != 0:
                return r.json()['data']
        except KeyError:
            return r.json()['error']

    async def set_if_idx(self, key, value, idx):
        """
        Represents a conditional set request to a data store,
        only supports new endpoints,

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        value
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        idx : int
            The expectedidx, there

        Returns
        -------
        typing.Any
        """
        url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}&usn=0.0"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': '*/*',
                'Content-Length': str(len(str(value)))
            }, data=quote(str(value)))
        if r.status_code == 409:
            usn = r.headers['roblox-usn']
            split = usn.split('.')
            msn_hash = split[0]
            current_value = split[1]
            url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}&usn={msn_hash}.{hex(idx).split('x')[1]}"
            r2 = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': '*/*',
                    'Content-Length': str(len(str(value)))
                }, data=quote(str(value)))
            if r2.status_code == 409:
                return "Expected idx did not match current idx, current idx is " + str(floor(int(current_value, 16)))
            else:
                return value

    async def increment(self, key, delta=0):
        """
        Represents a conditional set request to a data store,
        only supports legacy

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        delta : int, optional
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        
        Returns
        -------
        typing.Any
        """
        data = ""
        url = endpoint + f"persistence/increment?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&value={str(delta)}" if self.legacy_naming_scheme else endpoint + f"persistence/increment?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&value={str(delta)}"

        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        try:
            if r.json()['data'] != 0:
                return r.json()['data']
        except KeyError:
            cap = re.search("\(.+\)", r.json()['error'])
            reason = cap.group(0).replace("(", "").replace(")", "")
            if reason == "ExistingValueNotNumeric":
                return "The requested key you tried to increment had a different value other than byte, short, int, long, long long, float, double or long double"

    async def remove(self, key):
        """
        Represents a get request to a data store,
        using legacy works the same

        Parameters
        ----------
        key : str
            The key of the value you wish to remove, 
            as in the Second Parameter of 
            `void DataStore::removeAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`

        Returns
        -------
        typing.Any
        """
        if self.legacy:
            data = ""
            url = endpoint + f"persistence/remove?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme else endpoint + f"persistence/remove?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': 'application/x-www-form-urlencoded'
                }, data=data)
            if r.json()['data'] is None:
                return None
            else:
                return r.json()['data']
        else:
            url = endpoint + f"v1/persistence/ro_py/remove?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py/remove?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id)
                })
            if r.status_code == 204:
                return None
            else:
                return r.text

Classes

class DataStore (requests, place_id, name, scope, legacy=True, legacy_naming_scheme=False)

Represents the in-game datastore system for storing data for games (https://gamepersistence.roblox.com). This is only available for authenticated clients, and games that they own.

Parameters

requests : Requests
Requests object to use for API requests.
place_id : int
PlaceId to modify the DataStores for, if the currently authenticated user doesn't have sufficient permissions, it will raise a NotAuthorizedToModifyPlaceDataStores exception
name : str
The name of the DataStore, as in the Second Parameter of std::shared_ptr<RBX::Instance> DataStoreService::getDataStore(const DataStoreService* this, std::string name, std::string scope = "global")
scope : str, optional
The scope of the DataStore, as on the Second Parameter of std::shared_ptr<RBX::Instance> DataStoreService::getDataStore(const DataStoreService* this, std::string name, std::string scope = "global")
legacy : bool, optional
Describes whether or not this will use the legacy endpoints, over the new v1 endpoints (Does not apply to getSortedValues)
legacy_naming_scheme : bool, optional
Describes whether or not this will use legacy names for data stores, if true, the qkeys[idx].scope will match the current scope (global by default), there will be no qkeys[idx].target (normally the key that is passed into each method), and the qkeys[idx].key will match the key passed into each method.
Expand source code
class DataStore:
    """
    Represents the in-game datastore system for storing data for games (https://gamepersistence.roblox.com).
    This is only available for authenticated clients, and games that they own.

    Parameters
    ----------
    requests : ro_py.utilities.requests.Requests
        Requests object to use for API requests.
    place_id : int
        PlaceId to modify the DataStores for, 
        if the currently authenticated user doesn't have sufficient permissions, 
        it will raise a NotAuthorizedToModifyPlaceDataStores exception
    name : str
        The name of the DataStore, 
        as in the Second Parameter of 
        `std::shared_ptr<RBX::Instance> DataStoreService::getDataStore(const DataStoreService* this, std::string name, std::string scope = "global")`
    scope : str, optional
        The scope of the DataStore,
        as on the Second Parameter of
         `std::shared_ptr<RBX::Instance> DataStoreService::getDataStore(const DataStoreService* this, std::string name, std::string scope = "global")`
    legacy : bool, optional
        Describes whether or not this will use the legacy endpoints, 
        over the new v1 endpoints (Does not apply to getSortedValues)
    legacy_naming_scheme : bool, optional
        Describes whether or not this will use legacy names for data stores, if true, the qkeys[idx].scope will match the current scope (global by default), 
        there will be no qkeys[idx].target (normally the key that is passed into each method), 
        and the qkeys[idx].key will match the key passed into each method.
    """

    def __init__(self, requests, place_id, name, scope, legacy=True, legacy_naming_scheme=False):
        self.requests = requests
        self.place_id = place_id
        self.legacy = legacy
        self.legacy_naming_scheme = legacy_naming_scheme
        self.name = name
        self.scope = scope if scope is not None else "global"

    async def get(self, key):
        """
        Represents a get request to a data store,
        using legacy works the same

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        
        Returns
        -------
        typing.Any
        """
        if self.legacy:
            data = f"qkeys[0].scope={quote(self.scope)}&qkeys[0].target=&qkeys[0].key={quote(key)}" if self.legacy_naming_scheme == True else f"qkeys[0].scope={quote(self.scope)}&qkeys[0].target={quote(key)}&qkeys[0].key={quote(self.name)}"
            r = await self.requests.post(
                url=endpoint + f"persistence/getV2?placeId={str(self.place_id)}&type=standard&scope={quote(self.scope)}",
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': 'application/x-www-form-urlencoded'
                }, data=data)
            if len(r.json()['data']) == 0:
                return None
            else:
                return r.json()['data'][0]['Value']
        else:
            url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.get(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id)
                })
            if r.status_code == 204:
                return None
            else:
                return r.text

    async def set(self, key, value):
        """
        Represents a set request to a data store,
        using legacy works the same

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        value
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        
        Returns
        -------
        typing.Any
        """
        if self.legacy:
            data = f"value={quote(str(value))}"
            url = endpoint + f"persistence/set?placeId={self.place_id}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&valueLength={str(len(str(value)))}" if self.legacy_naming_scheme == True else endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&valueLength={str(len(str(value)))}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': 'application/x-www-form-urlencoded'
                }, data=data)
            if len(r.json()['data']) == 0:
                return None
            else:
                return r.json()['data']
        else:
            url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': '*/*',
                    'Content-Length': str(len(str(value)))
                }, data=quote(str(value)))
            if r.status_code == 200:
                return value

    async def set_if_value(self, key, value, expected_value):
        """
        Represents a conditional set request to a data store,
        only supports legacy

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        value
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        expected_value
            The expected_value for that key, if you know the key doesn't exist, then set this as None

        Returns
        -------
        typing.Any
        """
        data = f"value={quote(str(value))}&expectedValue={quote(str(expected_value)) if expected_value is not None else ''}"
        url = endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&valueLength={str(len(str(value)))}&expectedValueLength={str(len(str(expected_value))) if expected_value is not None else str(0)}" if self.legacy_naming_scheme == True else endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&valueLength={str(len(str(value)))}&expectedValueLength={str(len(str(expected_value))) if expected_value is not None else str(0)}"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        try:
            if r.json()['data'] != 0:
                return r.json()['data']
        except KeyError:
            return r.json()['error']

    async def set_if_idx(self, key, value, idx):
        """
        Represents a conditional set request to a data store,
        only supports new endpoints,

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        value
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        idx : int
            The expectedidx, there

        Returns
        -------
        typing.Any
        """
        url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}&usn=0.0"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': '*/*',
                'Content-Length': str(len(str(value)))
            }, data=quote(str(value)))
        if r.status_code == 409:
            usn = r.headers['roblox-usn']
            split = usn.split('.')
            msn_hash = split[0]
            current_value = split[1]
            url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}&usn={msn_hash}.{hex(idx).split('x')[1]}"
            r2 = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': '*/*',
                    'Content-Length': str(len(str(value)))
                }, data=quote(str(value)))
            if r2.status_code == 409:
                return "Expected idx did not match current idx, current idx is " + str(floor(int(current_value, 16)))
            else:
                return value

    async def increment(self, key, delta=0):
        """
        Represents a conditional set request to a data store,
        only supports legacy

        Parameters
        ----------
        key : str
            The key of the value you wish to get, 
            as in the Second Parameter of 
            `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
        delta : int, optional
            The value to set for the key,
            as in the 3rd parameter of
            `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
        
        Returns
        -------
        typing.Any
        """
        data = ""
        url = endpoint + f"persistence/increment?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&value={str(delta)}" if self.legacy_naming_scheme else endpoint + f"persistence/increment?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&value={str(delta)}"

        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        try:
            if r.json()['data'] != 0:
                return r.json()['data']
        except KeyError:
            cap = re.search("\(.+\)", r.json()['error'])
            reason = cap.group(0).replace("(", "").replace(")", "")
            if reason == "ExistingValueNotNumeric":
                return "The requested key you tried to increment had a different value other than byte, short, int, long, long long, float, double or long double"

    async def remove(self, key):
        """
        Represents a get request to a data store,
        using legacy works the same

        Parameters
        ----------
        key : str
            The key of the value you wish to remove, 
            as in the Second Parameter of 
            `void DataStore::removeAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`

        Returns
        -------
        typing.Any
        """
        if self.legacy:
            data = ""
            url = endpoint + f"persistence/remove?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme else endpoint + f"persistence/remove?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id),
                    'Content-Type': 'application/x-www-form-urlencoded'
                }, data=data)
            if r.json()['data'] is None:
                return None
            else:
                return r.json()['data']
        else:
            url = endpoint + f"v1/persistence/ro_py/remove?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py/remove?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
            r = await self.requests.post(
                url=url,
                headers={
                    'Roblox-Place-Id': str(self.place_id)
                })
            if r.status_code == 204:
                return None
            else:
                return r.text

Methods

async def get(self, key)

Represents a get request to a data store, using legacy works the same

Parameters

key : str
The key of the value you wish to get, as in the Second Parameter of void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)

Returns

typing.Any
 
Expand source code
async def get(self, key):
    """
    Represents a get request to a data store,
    using legacy works the same

    Parameters
    ----------
    key : str
        The key of the value you wish to get, 
        as in the Second Parameter of 
        `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
    
    Returns
    -------
    typing.Any
    """
    if self.legacy:
        data = f"qkeys[0].scope={quote(self.scope)}&qkeys[0].target=&qkeys[0].key={quote(key)}" if self.legacy_naming_scheme == True else f"qkeys[0].scope={quote(self.scope)}&qkeys[0].target={quote(key)}&qkeys[0].key={quote(self.name)}"
        r = await self.requests.post(
            url=endpoint + f"persistence/getV2?placeId={str(self.place_id)}&type=standard&scope={quote(self.scope)}",
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        if len(r.json()['data']) == 0:
            return None
        else:
            return r.json()['data'][0]['Value']
    else:
        url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
        r = await self.requests.get(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id)
            })
        if r.status_code == 204:
            return None
        else:
            return r.text
async def increment(self, key, delta=0)

Represents a conditional set request to a data store, only supports legacy

Parameters

key : str
The key of the value you wish to get, as in the Second Parameter of void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)
delta : int, optional
The value to set for the key, as in the 3rd parameter of void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)

Returns

typing.Any
 
Expand source code
async def increment(self, key, delta=0):
    """
    Represents a conditional set request to a data store,
    only supports legacy

    Parameters
    ----------
    key : str
        The key of the value you wish to get, 
        as in the Second Parameter of 
        `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
    delta : int, optional
        The value to set for the key,
        as in the 3rd parameter of
        `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
    
    Returns
    -------
    typing.Any
    """
    data = ""
    url = endpoint + f"persistence/increment?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&value={str(delta)}" if self.legacy_naming_scheme else endpoint + f"persistence/increment?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&value={str(delta)}"

    r = await self.requests.post(
        url=url,
        headers={
            'Roblox-Place-Id': str(self.place_id),
            'Content-Type': 'application/x-www-form-urlencoded'
        }, data=data)
    try:
        if r.json()['data'] != 0:
            return r.json()['data']
    except KeyError:
        cap = re.search("\(.+\)", r.json()['error'])
        reason = cap.group(0).replace("(", "").replace(")", "")
        if reason == "ExistingValueNotNumeric":
            return "The requested key you tried to increment had a different value other than byte, short, int, long, long long, float, double or long double"
async def remove(self, key)

Represents a get request to a data store, using legacy works the same

Parameters

key : str
The key of the value you wish to remove, as in the Second Parameter of void DataStore::removeAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)

Returns

typing.Any
 
Expand source code
async def remove(self, key):
    """
    Represents a get request to a data store,
    using legacy works the same

    Parameters
    ----------
    key : str
        The key of the value you wish to remove, 
        as in the Second Parameter of 
        `void DataStore::removeAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`

    Returns
    -------
    typing.Any
    """
    if self.legacy:
        data = ""
        url = endpoint + f"persistence/remove?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme else endpoint + f"persistence/remove?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        if r.json()['data'] is None:
            return None
        else:
            return r.json()['data']
    else:
        url = endpoint + f"v1/persistence/ro_py/remove?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py/remove?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id)
            })
        if r.status_code == 204:
            return None
        else:
            return r.text
async def set(self, key, value)

Represents a set request to a data store, using legacy works the same

Parameters

key : str
The key of the value you wish to get, as in the Second Parameter of void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)
value
The value to set for the key, as in the 3rd parameter of void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)

Returns

typing.Any
 
Expand source code
async def set(self, key, value):
    """
    Represents a set request to a data store,
    using legacy works the same

    Parameters
    ----------
    key : str
        The key of the value you wish to get, 
        as in the Second Parameter of 
        `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
    value
        The value to set for the key,
        as in the 3rd parameter of
        `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
    
    Returns
    -------
    typing.Any
    """
    if self.legacy:
        data = f"value={quote(str(value))}"
        url = endpoint + f"persistence/set?placeId={self.place_id}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&valueLength={str(len(str(value)))}" if self.legacy_naming_scheme == True else endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&valueLength={str(len(str(value)))}"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': 'application/x-www-form-urlencoded'
            }, data=data)
        if len(r.json()['data']) == 0:
            return None
        else:
            return r.json()['data']
    else:
        url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}"
        r = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': '*/*',
                'Content-Length': str(len(str(value)))
            }, data=quote(str(value)))
        if r.status_code == 200:
            return value
async def set_if_idx(self, key, value, idx)

Represents a conditional set request to a data store, only supports new endpoints,

Parameters

key : str
The key of the value you wish to get, as in the Second Parameter of void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)
value
The value to set for the key, as in the 3rd parameter of void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)
idx : int
The expectedidx, there

Returns

typing.Any
 
Expand source code
async def set_if_idx(self, key, value, idx):
    """
    Represents a conditional set request to a data store,
    only supports new endpoints,

    Parameters
    ----------
    key : str
        The key of the value you wish to get, 
        as in the Second Parameter of 
        `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
    value
        The value to set for the key,
        as in the 3rd parameter of
        `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
    idx : int
        The expectedidx, there

    Returns
    -------
    typing.Any
    """
    url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}&usn=0.0"
    r = await self.requests.post(
        url=url,
        headers={
            'Roblox-Place-Id': str(self.place_id),
            'Content-Type': '*/*',
            'Content-Length': str(len(str(value)))
        }, data=quote(str(value)))
    if r.status_code == 409:
        usn = r.headers['roblox-usn']
        split = usn.split('.')
        msn_hash = split[0]
        current_value = split[1]
        url = endpoint + f"v1/persistence/ro_py?type=standard&key={quote(key)}&scope={quote(self.scope)}&target=" if self.legacy_naming_scheme == True else endpoint + f"v1/persistence/ro_py?type=standard&key={quote(self.name)}&scope={quote(self.scope)}&target={quote(key)}&usn={msn_hash}.{hex(idx).split('x')[1]}"
        r2 = await self.requests.post(
            url=url,
            headers={
                'Roblox-Place-Id': str(self.place_id),
                'Content-Type': '*/*',
                'Content-Length': str(len(str(value)))
            }, data=quote(str(value)))
        if r2.status_code == 409:
            return "Expected idx did not match current idx, current idx is " + str(floor(int(current_value, 16)))
        else:
            return value
async def set_if_value(self, key, value, expected_value)

Represents a conditional set request to a data store, only supports legacy

Parameters

key : str
The key of the value you wish to get, as in the Second Parameter of void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)
value
The value to set for the key, as in the 3rd parameter of void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)
expected_value
The expected_value for that key, if you know the key doesn't exist, then set this as None

Returns

typing.Any
 
Expand source code
async def set_if_value(self, key, value, expected_value):
    """
    Represents a conditional set request to a data store,
    only supports legacy

    Parameters
    ----------
    key : str
        The key of the value you wish to get, 
        as in the Second Parameter of 
        `void DataStore::getAsync(const DataStore* this, std::string key, boost::function<void(RBX::Reflection::Variant)> resumeFunction, boost::function<void(std::string)> errorFunction)`
    value
        The value to set for the key,
        as in the 3rd parameter of
        `void DataStore::setAsync(const DataStore* this, std::string key, RBX::Reflection::Variant value, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction)`
    expected_value
        The expected_value for that key, if you know the key doesn't exist, then set this as None

    Returns
    -------
    typing.Any
    """
    data = f"value={quote(str(value))}&expectedValue={quote(str(expected_value)) if expected_value is not None else ''}"
    url = endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(key)}&type=standard&scope={quote(self.scope)}&target=&valueLength={str(len(str(value)))}&expectedValueLength={str(len(str(expected_value))) if expected_value is not None else str(0)}" if self.legacy_naming_scheme == True else endpoint + f"persistence/set?placeId={str(self.place_id)}&type=standard&key={quote(self.name)}&type=standard&scope={quote(self.scope)}&target={quote(key)}&valueLength={str(len(str(value)))}&expectedValueLength={str(len(str(expected_value))) if expected_value is not None else str(0)}"
    r = await self.requests.post(
        url=url,
        headers={
            'Roblox-Place-Id': str(self.place_id),
            'Content-Type': 'application/x-www-form-urlencoded'
        }, data=data)
    try:
        if r.json()['data'] != 0:
            return r.json()['data']
    except KeyError:
        return r.json()['error']