Implement live syncback service properties encoding and enhance syncback functionality

- Introduced a new `encodeService` helper in the plugin to serialize service properties, attributes, tags, and references alongside children data.
- Updated the `performSyncback` function to utilize the new encoding method, ensuring all services are processed without child-only restrictions.
- Extended the `ServiceChunk` struct to include fields for properties, attributes, tags, and references, improving data handling during syncback.
- Modified the `build_dom_from_chunks` function to apply service properties and resolve references when reconstructing the service instances.
- Added comprehensive tests to validate the new service properties handling, ensuring accurate synchronization and data integrity.

These enhancements significantly improve the live syncback process, allowing for better service data management and consistency.
This commit is contained in:
Joe 2026-02-18 07:22:29 -06:00
parent 30e032b27e
commit 72ad84b5a7
16 changed files with 896 additions and 444 deletions

View file

@ -0,0 +1,101 @@
local SerializationService = game:GetService("SerializationService")
local Packages = script.Parent.Parent.Parent.Packages
local Log = require(Packages.Log)
local RbxDom = require(Packages.RbxDom)
local encodeProperty = require(script.Parent.encodeProperty)
local UNENCODABLE_DATA_TYPES = require(script.Parent.propertyFilter)
local SKIP_PROPERTIES = {
Parent = true,
Name = true,
Archivable = true,
}
return function(service: Instance)
local properties = {}
local attributes = {}
local tags = {}
local refs = {}
local classDescriptor = RbxDom.findClassDescriptor(service.ClassName)
if classDescriptor then
for propertyName, propertyMeta in pairs(classDescriptor.properties) do
if SKIP_PROPERTIES[propertyName] then
continue
end
if propertyName == "Attributes" or propertyName == "Tags" then
continue
end
local isReadable = propertyMeta.scriptability == "ReadWrite" or propertyMeta.scriptability == "Read"
local doesSerialize = propertyMeta.serialization ~= "DoesNotSerialize"
if isReadable and doesSerialize then
local descriptor = RbxDom.findCanonicalPropertyDescriptor(service.ClassName, propertyName)
if descriptor then
if UNENCODABLE_DATA_TYPES[descriptor.dataType] then
continue
end
if descriptor.dataType == "Ref" then
local readOk, target = descriptor:read(service)
if readOk and target and target.Parent == service then
refs[propertyName] = {
name = target.Name,
className = target.ClassName,
}
end
continue
end
local encodeOk, encoded = encodeProperty(service, propertyName, descriptor)
if encodeOk and encoded ~= nil then
properties[propertyName] = encoded
end
end
end
end
end
local attrOk, attrMap = pcall(function()
return service:GetAttributes()
end)
if attrOk and attrMap and next(attrMap) then
local descriptor = RbxDom.findCanonicalPropertyDescriptor(service.ClassName, "Attributes")
if descriptor then
local encodeOk, encoded = encodeProperty(service, "Attributes", descriptor)
if encodeOk and encoded ~= nil then
attributes = encoded
end
end
end
local tagOk, tagList = pcall(function()
return service:GetTags()
end)
if tagOk and tagList and #tagList > 0 then
tags = tagList
end
local children = service:GetChildren()
local data = buffer.create(0)
if #children > 0 then
local serializeOk, result = pcall(SerializationService.SerializeInstancesAsync, SerializationService, children)
if serializeOk then
data = result
else
Log.warn("Failed to serialize children of {}: {}", service.ClassName, tostring(result))
end
end
return {
className = service.ClassName,
data = data,
properties = properties,
attributes = attributes,
tags = tags,
refs = refs,
}
end