Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use clone_multiple_into_external in Document instance methods #117

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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