PlaceFile

A whole place or Model as Roblox instances you can walk, change and save back, in either format.

Find an instance by a dotted or slash path with FindInstance, set its properties and attributes, then SaveAsync. Kind comes from the file name's ending and Format from its first bytes. A place's tree is DataModel; a Model's roots are in Instances. A few derived properties can't be read inside a file: use RobloxFileService:GetWorldCFrame for an Attachment and part.CFrame.Position for a part's position. GetPivot works.

ShotInstancenot creatableRoblox

Call RobloxFileService:OpenAsync, FromBuffer or New.

Example

A place built in memoryLuau
--!strict
-- A place built in memory: add a folder, find it by path, copy the file, write it as XML and read it back.
local RobloxFileService = require("@shotsystem/RobloxFileService")

-- a Model's bytes in XML: a Shop folder holding an Apple
local kit = assert(RobloxFileService:FromBuffer([[<roblox version="4">
<Item class="Folder" referent="A"><Properties><string name="Name">Shop</string></Properties>
<Item class="StringValue" referent="B"><Properties><string name="Name">Apple</string><string name="Value">red</string></Properties></Item>
</Item></roblox>]], "Model"))
local place = RobloxFileService:New("Place")
print("new:", place.Kind, place.Format, place.Path, place.ReadOnly, #place.Instances)
kit.Instances[1]:Clone().Parent = assert(place.DataModel):GetService("ReplicatedStorage")

local function apple(file : PlaceFile) : any -- the Apple, by a dotted path from game
	return assert(file:FindInstance("ReplicatedStorage.Shop.Apple"))
end
print("dotted path:", apple(place).Value, "slash path:", assert(place:FindInstance("ReplicatedStorage/Shop/Apple")).Name)
print("not there:", place:FindInstance("ReplicatedStorage.Shop.Pear"))
-- a Clone is a file of its own: changing it leaves the original alone
local copy = place:Clone()
apple(copy).Value = "green"
print("copy:", apple(copy).Value, "original:", apple(place).Value)
local xml = place:ToBuffer("Xml")
local back = assert(RobloxFileService:FromBuffer(xml, "Place"))
print("XML read back:", buffer.readstring(xml, 0, 7), back.Format, apple(back).Value)
for _, file in { kit, place, copy, back } do
	file:Close()
end
local ok, why = pcall(function() return place.DataModel end)
print("after Close:", ok, (string.gsub(tostring(why), "^.-:%d+: ", "")))
What it printedOutput
new: Place Binary nil false 0
dotted path: red slash path: Apple
not there: nil
copy: green original: red
XML read back: <roblox Xml red
after Close: false PlaceFile "Place" was destroyed

Properties

NameTypeDefaultDescription
Pathstring?read-onlyThe file it was opened from or last saved to; nil for one made by New, FromBuffer or Clone until it is saved.
Kind"Place" | "Model""Place"
read-only
Place or Model, taken from the file name's ending only; New and FromBuffer take it from their argument.
Format"Binary" | "Xml""Binary"
read-only
Binary or Xml, read from the file's first bytes rather than its name, and changed by each SaveAsync to the format written.
DataModelRobloxInstance?read-onlyThe place's whole instance tree when Kind is Place, else nil; Close destroys it.
Instances{ RobloxInstance }read-onlyA Model's top-level instances, a live list you can add to with table.insert; for a place it is empty, use DataModel.
GameNamestring?read-only
ReadOnlybooleanfalse
read-only
True when opened with { ReadOnly = true }: SaveAsync then returns false and why, and the property itself can't be set.

Methods

NameArgumentsReturnsDescription
FindInstance(path: string)RobloxInstance?An instance by a dotted path (ReplicatedStorage.Shared.Config) or a slash path, else nil; a Model's paths start at a top-level instance.
ToBuffer(format: ("Binary" | "Xml")?)bufferThe file's bytes in the format given, else in its own Format; any format but Binary or Xml is an error.
SaveAsync
yields
(path: string?, format: ("Binary" | "Xml")?)(boolean, string?)Waits until the file is written to path, else its own Path, through a temporary file; the format given, else the path's ending's, else Format.
Close()()Destroys the file and its DataModel; a Model's instances go only while still top level, so ones you moved elsewhere survive.
Clone()PlaceFileA new open PlaceFile holding a copy of the tree, as saving and reopening would give, cross references kept; its Path is nil.
From ShotInstance 33