the cutting room mirror

Official Places

This page contains notes for the page Roblox (Engine)/Revisional Differences/Official Places.

Place files archives#

Experimental Jet Pack

Downloading uncopylocked place files#

After some time I got Gemini to spit out this code, which allows you to download all place files that exist for a game using Python. To get the max. place number check out the next paragraph.

import requests
import os
import time

def download_roblox_place_versions(place_id, start_version, end_version, output_directory="."):
    """
    Downloads a range of versions of a Roblox place and adds the .rbxl extension.

    Args:
        place_id: The ID of the Roblox place (an integer).
        start_version: The first version number to download (an integer).
        end_version: The last version number to download (an integer).
        output_directory: The directory where downloaded files will be saved. Defaults to the current directory.
    """
    os.makedirs(output_directory, exist_ok=True)  # Create output directory

    for version_number in range(start_version, end_version + 1): # +1 so that end_version is included
        url = f"https://assetdelivery.roblox.com/v1/asset/?id={place_id}&version={version_number}"

        try:
            response = requests.get(url, stream=True)
            response.raise_for_status()

            file_name = f"{place_id}_v{version_number}.rbxl"
            file_path = os.path.join(output_directory, file_name)

            with open(file_path, "wb") as f:
                for chunk in response.iter_content(chunk_size=8192):
                    f.write(chunk)

            print(f"Downloaded place version {version_number} to {file_path}")

        except requests.exceptions.RequestException as e:
            print(f"Error downloading version {version_number}: {e}")
        except OSError as e:
            print(f"OS Error with version {version_number}: {e}")
            
        time.sleep(2)  # Wait for 2 seconds before the next request

# Example usage:
place_id = 1437  # Replace with the actual place ID
start_version = 0  # Replace with the desired starting version
end_version = 112    # Replace with the desired ending version
download_roblox_place_versions(place_id, start_version, end_version)

Get max. place version#

To get the currently published place version which tends to be the newest place version you can use this python code. (To use this you need an API key from here with read access to the asset API.)

import requests

api_key = "REPLACETHISWITHYOURAPIKEY" #Replace with your api key

def get_asset_revision_id(asset_id, api_key, read_mask="revisionId"):
  url = f"https://apis.roblox.com/assets/v1/assets/{asset_id}?readMask={read_mask}"
  headers = {
      "x-api-key": api_key
  }

  try:
    response = requests.get(url, headers=headers)
    response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
    data = response.json()
    return data.get("revisionId")  # Safely get the revisionId from the response
  except requests.exceptions.RequestException as e:
    print(f"An error occurred: {e}")
    return None
  except ValueError: #if the json cannot be decoded.
    print("Invalid JSON response")
    return None
  except KeyError: #if the revisionId is not in the json
    print("revisionId not found in response")
    return None

asset_id = input("Asset ID (example: 1437): ")
revision_id = get_asset_revision_id(asset_id, api_key)

if revision_id is not None:
  print(f"Revision ID: {revision_id}")

Making an asset tree#

I made the asset tree using the following script, the script needs to be put into the ServerScriptService as a normal script.

local function printTree(prefix, name, classname)
    if not classname then
        script.Value.Value = script.Value.Value .. prefix .. name .. "\n"
    else
        script.Value.Value = script.Value.Value .. prefix .. name .. " (" .. classname .. ")\n"
    end
end

local function traverse(parent, prefix)
    for _, child in ipairs(parent:GetChildren()) do
        printTree(prefix, child.Name, child.ClassName)
        traverse(child, prefix .. "  ")
    end
end

local services = {
    game:GetService("Workspace"),
    game:GetService("ReplicatedStorage"),
    game:GetService("ReplicatedFirst"),
    game:GetService("ServerStorage"),
    game:GetService("ServerScriptService"),
    game:GetService("StarterPack"),
    game:GetService("StarterGui"),
    game:GetService("StarterPlayer"),
}

for _, service in ipairs(services) do
    printTree("", service.Name)
    traverse(service, "  ")
end

For this code to work you need to run it and you need to put a child StringValue inside of the script. It should look like the example tree below.

ServerScriptService
└── Script (Script)
    └── Value (StringValue)

After running the code, make sure you're looking at the game on the serverside. Copy the value found in the StringValue and paste it into [https://tree.nathanfriend.io/?s=(%27options!(%27fancy!true~fullPath*~trailingSlash*~rootDot*)~-(%27-%27%27)~version!%271%27)*!false-source!%01-* this website.] Now copy the tree using the Copy button found at the top of the screen and put the tree into the page surrounded by the following code.

Code#

<pre style='white-space: pre-wrap; overflow: auto; width: 700px'; height: 300px'>

</pre>

Getting the time an asset was updated for the last time#

Well just put this code into a script located inside of ServerScriptService. (This is for the specific versions of experiences.)

local asset = game:GetService("MarketplaceService"):GetProductInfo(PutYourAssetIdHere, Enum.InfoType.Asset, VersionValue)
local update_stamp = tostring(asset.Updated)

function ConvertTimeStamp(time_stamp)
    local date_pattern = "%d%d%d%d%-%d%d%-%d%d"
    local stamp_date = string.sub(time_stamp, string.find(time_stamp, date_pattern))

    local split_date = string.split(stamp_date, "-")

    local year = split_date[1]
    local month = split_date[2]
    local day = split_date[3]

    local elapsed_years = (year - 1970)
    local elapsed_months = month - 1
    local elapsed_days = day - 1

    return year, month, day
end

print(ConvertTimeStamp(update_stamp))

Use this if you want the overall last update time:

local asset = game:GetService(“MarketplaceService”):GetProductInfo(PutYourAssetIdHere)
local update_stamp = tostring(asset.Updated)

function ConvertTimeStamp(time_stamp)
    local date_pattern = “%d%d%d%d%A%d%d%A%d%d”
    local stamp_date = string.sub(time_stamp, string.find(time_stamp, date_pattern))

    local split_date = string.split(stamp_date, “-”)

    local year = split_date[1]
    local month = split_date[2]
    local day = split_date[3]

    local elapsed_years = (year - 1970)
    local elapsed_months = month - 1
    local elapsed_days = day - 1

    return year, month, day
end

print(ConvertTimeStamp(update_stamp))