Module ro_py.games

This file houses functions and classes that pertain to Roblox universes and places.

Expand source code
"""

This file houses functions and classes that pertain to Roblox universes and places.

"""

from ro_py.utilities.clientobject import ClientObject
from ro_py.thumbnails import GameThumbnailGenerator
from ro_py.utilities.errors import GameJoinError
from ro_py.bases.baseuser import PartialUser
from ro_py.bases.baseasset import BaseAsset
from ro_py.utilities.cache import CacheType
from ro_py.groups import Group
from ro_py.badges import Badge
import subprocess
import json
import os

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


class Votes:
    """
    Represents a game's votes.
    """
    def __init__(self, votes_data):
        self.up_votes = votes_data["upVotes"]
        self.down_votes = votes_data["downVotes"]


class Game(ClientObject):
    """
    Represents a Roblox game universe.
    This class represents multiple game-related endpoints.
    """
    def __init__(self, cso, universe_id):
        super().__init__()
        self.id = universe_id
        self.cso = cso
        self.requests = cso.requests
        self.name = None
        self.root_place_id = None
        self.description = None
        self.creator = None
        self.price = None
        self.allowed_gear_genres = None
        self.allowed_gear_categories = None
        self.playing = None
        self.visits = None
        self.max_players = None
        self.studio_access_to_apis_allowed = None
        self.create_vip_servers_allowed = None
        self.thumbnails = GameThumbnailGenerator(self.requests, self.id)

    async def update(self):
        """
        Updates the game's information.
        """
        game_info_req = await self.requests.get(
            url=endpoint + "v1/games",
            params={
                "universeIds": str(self.id)
            }
        )
        game_info = game_info_req.json()
        game_info = game_info["data"][0]
        self.name = game_info["name"]
        self.root_place_id = game_info["rootPlaceId"]
        self.description = game_info["description"]
        if game_info["creator"]["type"] == "User":
            self.creator = self.cso.cache.get(CacheType.Users, game_info["creator"]["id"])
            if not self.creator:
                self.creator = await self.cso.client.get_user(game_info["creator"]["id"])
                self.cso.cache.set(CacheType.Users, game_info["creator"]["id"], self.creator)
                await self.creator.update()
        elif game_info["creator"]["type"] == "Group":
            self.creator = self.cso.cache.get(CacheType.Groups, game_info["creator"]["id"])
            if not self.creator:
                self.creator = Group(self.cso, game_info["creator"]["id"])
                self.cso.cache.set(CacheType.Groups, game_info["creator"]["id"], self.creator)
                await self.creator.update()
        self.price = game_info["price"]
        self.allowed_gear_genres = game_info["allowedGearGenres"]
        self.allowed_gear_categories = game_info["allowedGearCategories"]
        self.playing = game_info["playing"]
        self.visits = game_info["visits"]
        self.max_players = game_info["maxPlayers"]
        self.studio_access_to_apis_allowed = game_info["studioAccessToApisAllowed"]
        self.create_vip_servers_allowed = game_info["createVipServersAllowed"]

    async def get_root_place(self):
        root_place = Place(self.cso, self.root_place_id, self)
        await root_place.update()
        return root_place

    async def get_votes(self):
        """
        Returns
        -------
        ro_py.games.Votes
        """
        votes_info_req = await self.requests.get(
            url=endpoint + "v1/games/votes",
            params={
                "universeIds": str(self.id)
            }
        )
        votes_info = votes_info_req.json()
        votes_info = votes_info["data"][0]
        votes = Votes(votes_info)
        return votes

    async def get_badges(self):
        """
        Gets the game's badges.
        This will be updated soon to use the new Page object.
        """
        badges_req = await self.requests.get(
            url=f"https://badges.roblox.com/v1/universes/{self.id}/badges",
            params={
                "limit": 100,
                "sortOrder": "Asc"
            }
        )
        badges_data = badges_req.json()["data"]
        badges = []
        for badge in badges_data:
            badges.append(Badge(self.cso, badge["id"]))
        return badges


class Place(ClientObject, BaseAsset):
    def __init__(self, cso, place_id, universe):
        super().__init__()
        self.cso = cso
        self.requests = cso.requests
        self.id = place_id
        self.universe = universe
        self.name = None
        self.description = None
        self.url = None
        self.creator = None
        self.is_playable = None
        self.reason_prohibited = None
        self.price = None

    async def update(self):
        place_req = await self.requests.get(
            url="https://games.roblox.com/v1/games/multiget-place-details",
            params={
                "placeIds": self.id
            }
        )
        place_data = place_req.json()[0]
        self.name = place_data["name"]
        self.description = place_data["description"]
        self.url = place_data["url"]
        self.creator = PartialUser(self.cso, place_data["builderId"], place_data["builder"])
        self.is_playable = place_data["isPlayable"]
        self.reason_prohibited = place_data["reasonProhibited"]
        self.price = place_data["price"]

    async def join(self, launchtime=1609186776825, rloc="en_us", gloc="en_us",
                   negotiate_url="https://www.roblox.com/Login/Negotiate.ashx"):
        """
        Joins the place.
        This currently only works on Windows since it looks in AppData for the executable.

        .. warning::
            Please *do not* use this part of ro.py maliciously. We've spent lots of time
            working on ro.py as a resource for building interactive Roblox programs, and
            we would hate to see it be used as a malicious tool.
            We do not condone any use of ro.py as an exploit and we are not responsible
            if you are banned from Roblox due to malicious use of our library.
        """
        local_app_data = os.getenv('LocalAppData')
        roblox_appdata_path = local_app_data + "\\Roblox"
        roblox_launcher = None

        app_storage = roblox_appdata_path + "\\LocalStorage"
        app_versions = roblox_appdata_path + "\\Versions"

        with open(app_storage + "\\appStorage.json") as app_storage_file:
            app_storage_data = json.load(app_storage_file)
        browser_tracker_id = app_storage_data["BrowserTrackerId"]

        for directory in os.listdir(app_versions):
            dir_path = app_versions + "\\" + directory
            if os.path.isdir(dir_path):
                if os.path.isfile(dir_path + "\\" + "RobloxPlayerBeta.exe"):
                    roblox_launcher = dir_path + "\\" + "RobloxPlayerBeta.exe"

        if not roblox_launcher:
            raise GameJoinError("Couldn't find RobloxPlayerBeta.exe.")

        ticket_req = self.requests.back_post(url="https://auth.roblox.com/v1/authentication-ticket/")
        auth_ticket = ticket_req.headers["rbx-authentication-ticket"]

        launch_url = "https://assetgame.roblox.com/game/PlaceLauncher.ashx" \
                     "?request=RequestGame" \
                     f"&browserTrackerId={browser_tracker_id}" \
                     f"&placeId={self.id}" \
                     "&isPlayTogetherGame=false"
        join_parameters = [
            roblox_launcher,
            "--play",
            "-a",
            negotiate_url,
            "-t",
            auth_ticket,
            "-j",
            launch_url,
            "-b",
            browser_tracker_id,
            "--launchtime=" + str(launchtime),
            "--rloc",
            rloc,
            "--gloc",
            gloc
        ]
        join_process = subprocess.run(
            args=join_parameters,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        return join_process.stdout, join_process.stderr

Classes

class Game (cso, universe_id)

Represents a Roblox game universe. This class represents multiple game-related endpoints.

Expand source code
class Game(ClientObject):
    """
    Represents a Roblox game universe.
    This class represents multiple game-related endpoints.
    """
    def __init__(self, cso, universe_id):
        super().__init__()
        self.id = universe_id
        self.cso = cso
        self.requests = cso.requests
        self.name = None
        self.root_place_id = None
        self.description = None
        self.creator = None
        self.price = None
        self.allowed_gear_genres = None
        self.allowed_gear_categories = None
        self.playing = None
        self.visits = None
        self.max_players = None
        self.studio_access_to_apis_allowed = None
        self.create_vip_servers_allowed = None
        self.thumbnails = GameThumbnailGenerator(self.requests, self.id)

    async def update(self):
        """
        Updates the game's information.
        """
        game_info_req = await self.requests.get(
            url=endpoint + "v1/games",
            params={
                "universeIds": str(self.id)
            }
        )
        game_info = game_info_req.json()
        game_info = game_info["data"][0]
        self.name = game_info["name"]
        self.root_place_id = game_info["rootPlaceId"]
        self.description = game_info["description"]
        if game_info["creator"]["type"] == "User":
            self.creator = self.cso.cache.get(CacheType.Users, game_info["creator"]["id"])
            if not self.creator:
                self.creator = await self.cso.client.get_user(game_info["creator"]["id"])
                self.cso.cache.set(CacheType.Users, game_info["creator"]["id"], self.creator)
                await self.creator.update()
        elif game_info["creator"]["type"] == "Group":
            self.creator = self.cso.cache.get(CacheType.Groups, game_info["creator"]["id"])
            if not self.creator:
                self.creator = Group(self.cso, game_info["creator"]["id"])
                self.cso.cache.set(CacheType.Groups, game_info["creator"]["id"], self.creator)
                await self.creator.update()
        self.price = game_info["price"]
        self.allowed_gear_genres = game_info["allowedGearGenres"]
        self.allowed_gear_categories = game_info["allowedGearCategories"]
        self.playing = game_info["playing"]
        self.visits = game_info["visits"]
        self.max_players = game_info["maxPlayers"]
        self.studio_access_to_apis_allowed = game_info["studioAccessToApisAllowed"]
        self.create_vip_servers_allowed = game_info["createVipServersAllowed"]

    async def get_root_place(self):
        root_place = Place(self.cso, self.root_place_id, self)
        await root_place.update()
        return root_place

    async def get_votes(self):
        """
        Returns
        -------
        ro_py.games.Votes
        """
        votes_info_req = await self.requests.get(
            url=endpoint + "v1/games/votes",
            params={
                "universeIds": str(self.id)
            }
        )
        votes_info = votes_info_req.json()
        votes_info = votes_info["data"][0]
        votes = Votes(votes_info)
        return votes

    async def get_badges(self):
        """
        Gets the game's badges.
        This will be updated soon to use the new Page object.
        """
        badges_req = await self.requests.get(
            url=f"https://badges.roblox.com/v1/universes/{self.id}/badges",
            params={
                "limit": 100,
                "sortOrder": "Asc"
            }
        )
        badges_data = badges_req.json()["data"]
        badges = []
        for badge in badges_data:
            badges.append(Badge(self.cso, badge["id"]))
        return badges

Ancestors

Methods

async def get_badges(self)

Gets the game's badges. This will be updated soon to use the new Page object.

Expand source code
async def get_badges(self):
    """
    Gets the game's badges.
    This will be updated soon to use the new Page object.
    """
    badges_req = await self.requests.get(
        url=f"https://badges.roblox.com/v1/universes/{self.id}/badges",
        params={
            "limit": 100,
            "sortOrder": "Asc"
        }
    )
    badges_data = badges_req.json()["data"]
    badges = []
    for badge in badges_data:
        badges.append(Badge(self.cso, badge["id"]))
    return badges
async def get_root_place(self)
Expand source code
async def get_root_place(self):
    root_place = Place(self.cso, self.root_place_id, self)
    await root_place.update()
    return root_place
async def get_votes(self)

Returns

Votes
 
Expand source code
async def get_votes(self):
    """
    Returns
    -------
    ro_py.games.Votes
    """
    votes_info_req = await self.requests.get(
        url=endpoint + "v1/games/votes",
        params={
            "universeIds": str(self.id)
        }
    )
    votes_info = votes_info_req.json()
    votes_info = votes_info["data"][0]
    votes = Votes(votes_info)
    return votes
async def update(self)

Updates the game's information.

Expand source code
async def update(self):
    """
    Updates the game's information.
    """
    game_info_req = await self.requests.get(
        url=endpoint + "v1/games",
        params={
            "universeIds": str(self.id)
        }
    )
    game_info = game_info_req.json()
    game_info = game_info["data"][0]
    self.name = game_info["name"]
    self.root_place_id = game_info["rootPlaceId"]
    self.description = game_info["description"]
    if game_info["creator"]["type"] == "User":
        self.creator = self.cso.cache.get(CacheType.Users, game_info["creator"]["id"])
        if not self.creator:
            self.creator = await self.cso.client.get_user(game_info["creator"]["id"])
            self.cso.cache.set(CacheType.Users, game_info["creator"]["id"], self.creator)
            await self.creator.update()
    elif game_info["creator"]["type"] == "Group":
        self.creator = self.cso.cache.get(CacheType.Groups, game_info["creator"]["id"])
        if not self.creator:
            self.creator = Group(self.cso, game_info["creator"]["id"])
            self.cso.cache.set(CacheType.Groups, game_info["creator"]["id"], self.creator)
            await self.creator.update()
    self.price = game_info["price"]
    self.allowed_gear_genres = game_info["allowedGearGenres"]
    self.allowed_gear_categories = game_info["allowedGearCategories"]
    self.playing = game_info["playing"]
    self.visits = game_info["visits"]
    self.max_players = game_info["maxPlayers"]
    self.studio_access_to_apis_allowed = game_info["studioAccessToApisAllowed"]
    self.create_vip_servers_allowed = game_info["createVipServersAllowed"]
class Place (cso, place_id, universe)

Every object that is grabbable with client.get_x inherits this object.

Expand source code
class Place(ClientObject, BaseAsset):
    def __init__(self, cso, place_id, universe):
        super().__init__()
        self.cso = cso
        self.requests = cso.requests
        self.id = place_id
        self.universe = universe
        self.name = None
        self.description = None
        self.url = None
        self.creator = None
        self.is_playable = None
        self.reason_prohibited = None
        self.price = None

    async def update(self):
        place_req = await self.requests.get(
            url="https://games.roblox.com/v1/games/multiget-place-details",
            params={
                "placeIds": self.id
            }
        )
        place_data = place_req.json()[0]
        self.name = place_data["name"]
        self.description = place_data["description"]
        self.url = place_data["url"]
        self.creator = PartialUser(self.cso, place_data["builderId"], place_data["builder"])
        self.is_playable = place_data["isPlayable"]
        self.reason_prohibited = place_data["reasonProhibited"]
        self.price = place_data["price"]

    async def join(self, launchtime=1609186776825, rloc="en_us", gloc="en_us",
                   negotiate_url="https://www.roblox.com/Login/Negotiate.ashx"):
        """
        Joins the place.
        This currently only works on Windows since it looks in AppData for the executable.

        .. warning::
            Please *do not* use this part of ro.py maliciously. We've spent lots of time
            working on ro.py as a resource for building interactive Roblox programs, and
            we would hate to see it be used as a malicious tool.
            We do not condone any use of ro.py as an exploit and we are not responsible
            if you are banned from Roblox due to malicious use of our library.
        """
        local_app_data = os.getenv('LocalAppData')
        roblox_appdata_path = local_app_data + "\\Roblox"
        roblox_launcher = None

        app_storage = roblox_appdata_path + "\\LocalStorage"
        app_versions = roblox_appdata_path + "\\Versions"

        with open(app_storage + "\\appStorage.json") as app_storage_file:
            app_storage_data = json.load(app_storage_file)
        browser_tracker_id = app_storage_data["BrowserTrackerId"]

        for directory in os.listdir(app_versions):
            dir_path = app_versions + "\\" + directory
            if os.path.isdir(dir_path):
                if os.path.isfile(dir_path + "\\" + "RobloxPlayerBeta.exe"):
                    roblox_launcher = dir_path + "\\" + "RobloxPlayerBeta.exe"

        if not roblox_launcher:
            raise GameJoinError("Couldn't find RobloxPlayerBeta.exe.")

        ticket_req = self.requests.back_post(url="https://auth.roblox.com/v1/authentication-ticket/")
        auth_ticket = ticket_req.headers["rbx-authentication-ticket"]

        launch_url = "https://assetgame.roblox.com/game/PlaceLauncher.ashx" \
                     "?request=RequestGame" \
                     f"&browserTrackerId={browser_tracker_id}" \
                     f"&placeId={self.id}" \
                     "&isPlayTogetherGame=false"
        join_parameters = [
            roblox_launcher,
            "--play",
            "-a",
            negotiate_url,
            "-t",
            auth_ticket,
            "-j",
            launch_url,
            "-b",
            browser_tracker_id,
            "--launchtime=" + str(launchtime),
            "--rloc",
            rloc,
            "--gloc",
            gloc
        ]
        join_process = subprocess.run(
            args=join_parameters,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        return join_process.stdout, join_process.stderr

Ancestors

Methods

async def join(self, launchtime=1609186776825, rloc='en_us', gloc='en_us', negotiate_url='https://www.roblox.com/Login/Negotiate.ashx')

Joins the place. This currently only works on Windows since it looks in AppData for the executable.

Warning

Please do not use this part of ro.py maliciously. We've spent lots of time working on ro.py as a resource for building interactive Roblox programs, and we would hate to see it be used as a malicious tool. We do not condone any use of ro.py as an exploit and we are not responsible if you are banned from Roblox due to malicious use of our library.

Expand source code
async def join(self, launchtime=1609186776825, rloc="en_us", gloc="en_us",
               negotiate_url="https://www.roblox.com/Login/Negotiate.ashx"):
    """
    Joins the place.
    This currently only works on Windows since it looks in AppData for the executable.

    .. warning::
        Please *do not* use this part of ro.py maliciously. We've spent lots of time
        working on ro.py as a resource for building interactive Roblox programs, and
        we would hate to see it be used as a malicious tool.
        We do not condone any use of ro.py as an exploit and we are not responsible
        if you are banned from Roblox due to malicious use of our library.
    """
    local_app_data = os.getenv('LocalAppData')
    roblox_appdata_path = local_app_data + "\\Roblox"
    roblox_launcher = None

    app_storage = roblox_appdata_path + "\\LocalStorage"
    app_versions = roblox_appdata_path + "\\Versions"

    with open(app_storage + "\\appStorage.json") as app_storage_file:
        app_storage_data = json.load(app_storage_file)
    browser_tracker_id = app_storage_data["BrowserTrackerId"]

    for directory in os.listdir(app_versions):
        dir_path = app_versions + "\\" + directory
        if os.path.isdir(dir_path):
            if os.path.isfile(dir_path + "\\" + "RobloxPlayerBeta.exe"):
                roblox_launcher = dir_path + "\\" + "RobloxPlayerBeta.exe"

    if not roblox_launcher:
        raise GameJoinError("Couldn't find RobloxPlayerBeta.exe.")

    ticket_req = self.requests.back_post(url="https://auth.roblox.com/v1/authentication-ticket/")
    auth_ticket = ticket_req.headers["rbx-authentication-ticket"]

    launch_url = "https://assetgame.roblox.com/game/PlaceLauncher.ashx" \
                 "?request=RequestGame" \
                 f"&browserTrackerId={browser_tracker_id}" \
                 f"&placeId={self.id}" \
                 "&isPlayTogetherGame=false"
    join_parameters = [
        roblox_launcher,
        "--play",
        "-a",
        negotiate_url,
        "-t",
        auth_ticket,
        "-j",
        launch_url,
        "-b",
        browser_tracker_id,
        "--launchtime=" + str(launchtime),
        "--rloc",
        rloc,
        "--gloc",
        gloc
    ]
    join_process = subprocess.run(
        args=join_parameters,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    return join_process.stdout, join_process.stderr
async def update(self)
Expand source code
async def update(self):
    place_req = await self.requests.get(
        url="https://games.roblox.com/v1/games/multiget-place-details",
        params={
            "placeIds": self.id
        }
    )
    place_data = place_req.json()[0]
    self.name = place_data["name"]
    self.description = place_data["description"]
    self.url = place_data["url"]
    self.creator = PartialUser(self.cso, place_data["builderId"], place_data["builder"])
    self.is_playable = place_data["isPlayable"]
    self.reason_prohibited = place_data["reasonProhibited"]
    self.price = place_data["price"]
class Votes (votes_data)

Represents a game's votes.

Expand source code
class Votes:
    """
    Represents a game's votes.
    """
    def __init__(self, votes_data):
        self.up_votes = votes_data["upVotes"]
        self.down_votes = votes_data["downVotes"]