Skip to content

Commit

Permalink
Use clone_multiple_into_external in Document instance methods (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethloeffler authored Oct 4, 2023
1 parent 74d7f3d commit c43648f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 47 deletions.
18 changes: 9 additions & 9 deletions src/roblox/document/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rbx_dom_weak::{InstanceBuilder as DomInstanceBuilder, WeakDom};
use rbx_dom_weak::{types::Ref as DomRef, InstanceBuilder as DomInstanceBuilder, WeakDom};
use rbx_xml::{
DecodeOptions as XmlDecodeOptions, DecodePropertyBehavior as XmlDecodePropertyBehavior,
EncodeOptions as XmlEncodeOptions, EncodePropertyBehavior as XmlEncodePropertyBehavior,
Expand Down Expand Up @@ -247,11 +247,13 @@ impl Document {
}

let mut dom = WeakDom::new(DomInstanceBuilder::new("ROOT"));
let children: Vec<DomRef> = i
.get_children()
.iter()
.map(|instance| instance.dom_ref)
.collect();

for data_model_child in i.get_children() {
data_model_child.clone_into_external_dom(&mut dom);
}

Instance::clone_multiple_into_external_dom(&children, &mut dom);
postprocess_dom_for_place(&mut dom);

Ok(Self {
Expand All @@ -274,11 +276,9 @@ impl Document {
}

let mut dom = WeakDom::new(DomInstanceBuilder::new("ROOT"));
let instances: Vec<DomRef> = v.iter().map(|instance| instance.dom_ref).collect();

for instance in v {
instance.clone_into_external_dom(&mut dom);
}

Instance::clone_multiple_into_external_dom(&instances, &mut dom);
postprocess_dom_for_model(&mut dom);

Ok(Self {
Expand Down
15 changes: 15 additions & 0 deletions src/roblox/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ impl Instance {
cloned
}

pub fn clone_multiple_into_external_dom(
referents: &[DomRef],
external_dom: &mut WeakDom,
) -> Vec<DomRef> {
let dom = INTERNAL_DOM.lock().expect("Failed to lock document");

let cloned = dom.clone_multiple_into_external(referents, external_dom);

for referent in cloned.iter() {
external_dom.transfer_within(*referent, external_dom.root_ref());
}

cloned
}

/**
Clones the instance and all of its descendants, and orphans it.
Expand Down
62 changes: 42 additions & 20 deletions tests/roblox/files/serializeModel.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,53 @@ local fs = require("@lune/fs")
local roblox = require("@lune/roblox")
local Instance = roblox.Instance

local instances = {
Instance.new("Model"),
Instance.new("Part"),
}
-- Smoke tests
do
local instances = {
Instance.new("Model"),
Instance.new("Part"),
}

local modelAsBinary = roblox.serializeModel(instances)
local modelAsXml = roblox.serializeModel(instances, true)
local modelAsBinary = roblox.serializeModel(instances)
local modelAsXml = roblox.serializeModel(instances, true)

fs.writeFile("bin/temp-model.rbxm", modelAsBinary)
fs.writeFile("bin/temp-model.rbxmx", modelAsXml)
fs.writeFile("bin/temp-model.rbxm", modelAsBinary)
fs.writeFile("bin/temp-model.rbxmx", modelAsXml)

local savedFileBinary = fs.readFile("bin/temp-model.rbxm")
local savedFileXml = fs.readFile("bin/temp-model.rbxmx")
local savedFileBinary = fs.readFile("bin/temp-model.rbxm")
local savedFileXml = fs.readFile("bin/temp-model.rbxmx")

local savedBinary = roblox.deserializeModel(savedFileBinary)
local savedXml = roblox.deserializeModel(savedFileXml)
local savedBinary = roblox.deserializeModel(savedFileBinary)
local savedXml = roblox.deserializeModel(savedFileXml)

assert(savedBinary[1].Name ~= "ROOT")
assert(savedXml[1].Name ~= "ROOT")
assert(savedBinary[1].Name ~= "ROOT")
assert(savedXml[1].Name ~= "ROOT")

assert(savedBinary[1].Name ~= "DataModel")
assert(savedXml[1].Name ~= "DataModel")
assert(savedBinary[1].Name ~= "DataModel")
assert(savedXml[1].Name ~= "DataModel")

assert(savedBinary[1].ClassName == "Model")
assert(savedBinary[2].ClassName == "Part")
assert(savedBinary[1].ClassName == "Model")
assert(savedBinary[2].ClassName == "Part")

assert(savedXml[1].ClassName == "Model")
assert(savedXml[2].ClassName == "Part")
assert(savedXml[1].ClassName == "Model")
assert(savedXml[2].ClassName == "Part")
end

-- Ensure Ref properties are preserved across descendants of multi-root model siblings
do
local part = Instance.new("Part")

local particleEmitter = Instance.new("ParticleEmitter")
particleEmitter.Parent = part

local folder = Instance.new("Folder")

local objectValue = Instance.new("ObjectValue") :: any
objectValue.Value = particleEmitter
objectValue.Parent = folder

local serialized = roblox.serializeModel({ part, folder })
local deserialized = roblox.deserializeModel(serialized) :: any

assert(deserialized[2].ObjectValue.Value == deserialized[1].ParticleEmitter)
end
61 changes: 43 additions & 18 deletions tests/roblox/files/serializePlace.luau
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,55 @@ local fs = require("@lune/fs")
local roblox = require("@lune/roblox")
local Instance = roblox.Instance

local game = Instance.new("DataModel")
-- Smoke tests
do
local game = Instance.new("DataModel")

local workspace = game:GetService("Workspace")
local workspace = game:GetService("Workspace")

local model = Instance.new("Model")
local part = Instance.new("Part")
local model = Instance.new("Model")
local part = Instance.new("Part")

part.Parent = model
model.Parent = workspace
part.Parent = model
model.Parent = workspace

local placeAsBinary = roblox.serializePlace(game)
local placeAsXml = roblox.serializePlace(game, true)
local placeAsBinary = roblox.serializePlace(game)
local placeAsXml = roblox.serializePlace(game, true)

fs.writeFile("bin/temp-place.rbxl", placeAsBinary)
fs.writeFile("bin/temp-place.rbxlx", placeAsXml)
fs.writeFile("bin/temp-place.rbxl", placeAsBinary)
fs.writeFile("bin/temp-place.rbxlx", placeAsXml)

local savedFileBinary = fs.readFile("bin/temp-place.rbxl")
local savedFileXml = fs.readFile("bin/temp-place.rbxlx")
local savedFileBinary = fs.readFile("bin/temp-place.rbxl")
local savedFileXml = fs.readFile("bin/temp-place.rbxlx")

local savedBinary = roblox.deserializePlace(savedFileBinary)
local savedXml = roblox.deserializePlace(savedFileXml)
local savedBinary = roblox.deserializePlace(savedFileBinary)
local savedXml = roblox.deserializePlace(savedFileXml)

assert(savedBinary.Name ~= "ROOT")
assert(savedXml.Name ~= "ROOT")
assert(savedBinary.Name ~= "ROOT")
assert(savedXml.Name ~= "ROOT")

assert(savedBinary.ClassName == "DataModel")
assert(savedXml.ClassName == "DataModel")
assert(savedBinary.ClassName == "DataModel")
assert(savedXml.ClassName == "DataModel")
end

-- Ensure Ref properties are preserved across services
do
local game = Instance.new("DataModel")
local ReplicatedStorage = Instance.new("ReplicatedStorage")
local Workspace = Instance.new("Workspace")

Workspace.Parent = game
ReplicatedStorage.Parent = game

local part = Instance.new("Part")
part.Parent = ReplicatedStorage

local objectValue = Instance.new("ObjectValue") :: any
objectValue.Value = part
objectValue.Parent = Workspace

local serialized = roblox.serializePlace(game)
local deserialized = roblox.deserializePlace(serialized) :: any

assert(deserialized.Workspace.ObjectValue.Value == deserialized.ReplicatedStorage.Part)
end

0 comments on commit c43648f

Please sign in to comment.