initial work

This commit is contained in:
Joe 2026-02-14 10:56:25 -06:00
parent 252325a7de
commit bf65d8bfa8
7 changed files with 143 additions and 20 deletions

View file

@ -33,13 +33,13 @@ return function(instanceMap, propertyChanges, syncSourceOnly)
if syncSourceOnly then
-- Filter to only Source property when server is in source-only mode
if properties.Source then
local update = encodePatchUpdate(instance, instanceId, { Source = true })
local update = encodePatchUpdate(instance, instanceId, { Source = true }, instanceMap)
if update then
table.insert(patch.updated, update)
end
end
else
local update = encodePatchUpdate(instance, instanceId, properties)
local update = encodePatchUpdate(instance, instanceId, properties, instanceMap)
if update then
table.insert(patch.updated, update)
end

View file

@ -5,7 +5,9 @@ local RbxDom = require(Packages.RbxDom)
local encodeProperty = require(script.Parent.encodeProperty)
local UNENCODABLE_DATA_TYPES = require(script.Parent.propertyFilter)
return function(instance, instanceId, properties)
local NULL_REF = "00000000000000000000000000000000"
return function(instance, instanceId, properties, instanceMap)
local update = {
id = instanceId,
changedProperties = {},
@ -26,6 +28,36 @@ return function(instance, instanceId, properties)
continue
end
-- Ref properties are encoded using the InstanceMap to resolve
-- Studio Instance references to server-side Ref IDs.
if descriptor.dataType == "Ref" then
local readSuccess, readResult = descriptor:read(instance)
if not readSuccess then
Log.debug("Could not read Ref property {:?}.{}: {}", instance, propertyName, readResult)
continue
end
if readResult == nil then
-- Nil ref: encode as null ref
update.changedProperties[propertyName] = { Ref = NULL_REF }
elseif instanceMap then
local targetId = instanceMap.fromInstances[readResult]
if targetId then
update.changedProperties[propertyName] = { Ref = targetId }
else
Log.warn(
"Cannot sync Ref property {:?}.{}: target {:?} is not tracked by Atlas",
instance,
propertyName,
readResult
)
end
else
Log.warn("Cannot encode Ref property {:?}.{}: no InstanceMap provided", instance, propertyName)
end
continue
end
local encodeSuccess, encodeResult = encodeProperty(instance, propertyName, descriptor)
if not encodeSuccess then

View file

@ -4,12 +4,14 @@
Types listed here are skipped during property encoding because they
cannot be serialized to JSON or are meaningless for syncback.
Note: Ref properties are NOT blacklisted here. They are handled
specially in encodePatchUpdate.lua using the InstanceMap to resolve
Studio Instance references to server-side Ref IDs.
]]
-- Property data types that cannot be encoded standalone.
-- Matches the Variant::Ref / Variant::UniqueId filter in api.rs.
local UNENCODABLE_DATA_TYPES = {
Ref = true, -- Instance references; need the InstanceMap, not encodable standalone
UniqueId = true, -- Internal Roblox identifiers; not meaningful for syncback
}

View file

@ -779,6 +779,11 @@ function ServeSession:__confirmAndApplyInitialPatch(catchUpPatch, serverInfo)
local guid = HttpService:GenerateGUID(false)
local tempRef = string.gsub(guid, "-", ""):lower()
pullPatch.added[tempRef] = encoded
-- Note: We intentionally do NOT pre-insert into InstanceMap here.
-- The VFS watcher will process the written files and assign a
-- server-side Ref ID. Any Ref properties targeting this instance
-- will be deferred by the ChangeBatcher and resolved once the
-- server ID appears in the InstanceMap via forward-sync.
-- Log at info level since this is a major file creation operation
Log.info("[Pull] Create file: {} ({})", instancePath, instanceClass)
end