RobloxFileService

Open, change and save Roblox places and Models as files, with no Studio running: .rbxl, .rbxlx, .rbxm or .rbxmx, binary or XML.

OpenAsync reads a file into a PlaceFile, FromBuffer reads bytes and New starts an empty place or Model. Each open file is a child of this service until you close it. A failure of the world, such as a missing or broken file, comes back as nil and why; a mistake in your code, such as a wrong kind, is an error.

ShotInstanceservicenot creatableRoblox

A service: write use RobloxFileService.

Example

Places and Models from bytesLuau
--!strict
-- A new place made in memory, a Model read from XML text, the two put together and read back from bytes.
local RobloxFileService = require("@shotsystem/RobloxFileService")

-- an XML CFrame at x, y, z with no rotation
local function at(x : number, y : number, z : number) : string
	return `<CoordinateFrame name="CFrame"><X>{x}</X><Y>{y}</Y><Z>{z}</Z><R00>1</R00><R01>0</R01><R02>0</R02>`
		.. `<R10>0</R10><R11>1</R11><R12>0</R12><R20>0</R20><R21>0</R21><R22>1</R22></CoordinateFrame>`
end
local xml = `<roblox version="4"><Item class="Folder" referent="A"><Properties><string name="Name">Shop</string></Properties>`
	.. `<Item class="Part" referent="B"><Properties><string name="Name">Stand</string>{at(10, 2, 0)}</Properties>`
	.. `<Item class="Attachment" referent="C"><Properties><string name="Name">Sign</string>{at(0, 3, 0)}</Properties>`
	.. `</Item></Item></Item></roblox>`

local kit = assert(RobloxFileService:FromBuffer(xml, "Model"))
print("kit:", kit.Kind, kit.Format, #kit.Instances, kit.Instances[1].Name)
local sign = RobloxFileService:GetWorldCFrame(assert(kit:FindInstance("Shop.Stand.Sign"))).Position
print("the sign in the world:", sign.X, sign.Y, sign.Z)

local place = RobloxFileService:New("Place")
kit.Instances[1]:Clone().Parent = assert(place.DataModel):GetService("Workspace")
local back = assert(RobloxFileService:FromBuffer(place:ToBuffer(), "Place"))
print("read back:", back.Kind, back.Format, assert(back:FindInstance("Workspace.Shop.Stand")).ClassName)
print("open files:", #RobloxFileService:GetChildren())
for _, file in { kit, place, back } do
	file:Close()
end
print("open files after Close:", #RobloxFileService:GetChildren())
What it printedOutput
kit: Model Xml 1 Shop
the sign in the world: 10 5 0
read back: Place Binary Part
open files: 3
open files after Close: 0

Methods

NameArgumentsReturnsDescription
OpenAsync
yields
(path: string, options: { ReadOnly: boolean? }?)(PlaceFile?, string?)Waits to read the file and gives a PlaceFile under this service, or nil and why; { ReadOnly = true } refuses every save.
FromBuffer(bytes: buffer | string, kind: "Place" | "Model")(PlaceFile?, string?)A PlaceFile from a file's bytes, with no Path and its Format read from the bytes; broken bytes give nil and why.
New(kind: "Place" | "Model")PlaceFileAn empty place or Model in Binary format with no Path, so its first SaveAsync must be given one.
GetWorldCFrame(attachment: RobloxInstance)CFrameAn Attachment's WorldCFrame, since reading that property inside a file errors; passing anything but an Attachment is an error.
From ShotInstance 33