Enhance live syncback process with improved reference handling and float precision

- Implemented ObjectValue carriers for service-level references, allowing for accurate serialization of non-direct child references during syncback.
- Updated `encodeService` to include explicit handling of attributes and tags, ensuring they are properly encoded and preventing data loss.
- Refactored `build_dom_from_chunks` to manage ObjectValue carriers and resolve references correctly, enhancing data integrity.
- Truncated float values to f32 precision in `UnresolvedValue::from_variant`, aligning with rbxl storage requirements and improving consistency.

These changes address critical issues in the live syncback process, enhancing reliability and data accuracy.
This commit is contained in:
Joe 2026-02-18 09:11:59 -06:00
parent 7dc4f52793
commit 39c8bd41f4
8 changed files with 342 additions and 121 deletions

View file

@ -642,13 +642,18 @@ function App:performSyncback()
local services = {}
local allChildren = {}
local allCarriers = {}
for _, className in SYNCBACK_SERVICES do
local ok, service = pcall(game.FindService, game, className)
if ok and service then
local chunk = encodeService(service)
local chunk, refTargets = encodeService(service)
for _, child in service:GetChildren() do
table.insert(allChildren, child)
end
for _, carrier in refTargets do
table.insert(allChildren, carrier)
table.insert(allCarriers, carrier)
end
table.insert(services, chunk)
end
end
@ -658,6 +663,10 @@ function App:performSyncback()
data = SerializationService:SerializeInstancesAsync(allChildren)
end
for _, carrier in allCarriers do
carrier:Destroy()
end
local url = ("http://%s:%s/api/syncback"):format(host, port)
local body = Http.msgpackEncode({
protocolVersion = Config.protocolVersion,

View file

@ -11,16 +11,26 @@ local SKIP_PROPERTIES = {
Archivable = true,
}
local EXCLUDE_PROPERTIES = {
Lighting = { ClockTime = true },
}
return function(service: Instance)
local properties = {}
local refs = {}
local children = service:GetChildren()
local refTargets = {}
local classDescriptor = RbxDom.findClassDescriptor(service.ClassName)
if classDescriptor then
local classExcludes = EXCLUDE_PROPERTIES[service.ClassName]
for propertyName, propertyMeta in pairs(classDescriptor.properties) do
if SKIP_PROPERTIES[propertyName] then
continue
end
if classExcludes and classExcludes[propertyName] then
continue
end
if propertyName == "Attributes" or propertyName == "Tags" then
continue
end
@ -38,11 +48,12 @@ return function(service: Instance)
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,
}
if readOk and target then
local carrier = Instance.new("ObjectValue")
carrier.Name = propertyName
carrier.Value = target
table.insert(refTargets, carrier)
refs[propertyName] = #refTargets
end
continue
end
@ -84,7 +95,8 @@ return function(service: Instance)
local chunk = {
className = service.ClassName,
childCount = #service:GetChildren(),
childCount = #children,
refTargetCount = #refTargets,
}
if next(properties) then
chunk.properties = properties
@ -92,5 +104,5 @@ return function(service: Instance)
if next(refs) then
chunk.refs = refs
end
return chunk
return chunk, refTargets
end