Use clone_multiple_into_external in Document instance methods (#117)

This commit is contained in:
Kenneth Loeffler 2023-10-04 15:25:26 -04:00 committed by GitHub
parent 74d7f3d66f
commit c43648faec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 47 deletions

View file

@ -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,
@ -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 {
@ -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 {

View file

@ -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.

View file

@ -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

View file

@ -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