local invariant = require(script.Parent.Parent.invariant)
local PatchSet = require(script.Parent.Parent.PatchSet)
local setProperty = require(script.Parent.setProperty)
local decodeValue = require(script.Parent.decodeValue)
local function addAllToPatch(patchSet, virtualInstances, id)
local virtualInstance = virtualInstances[id]
patchSet.added[id] = virtualInstance
for _, childId in ipairs(virtualInstance.Children) do
addAllToPatch(patchSet, virtualInstances, childId)
end
end
function reifyInstance(deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
local unappliedPatch = PatchSet.newEmpty()
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, rootId, parentInstance)
return unappliedPatch
end
function reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, id, parentInstance)
local virtualInstance = virtualInstances[id]
if virtualInstance == nil then
invariant("Cannot reify an instance not present in virtualInstances\nID: {}", id)
end
local createSuccess, instance = pcall(Instance.new, virtualInstance.ClassName)
if not createSuccess then
addAllToPatch(unappliedPatch, virtualInstances, id)
return
end
instance.Name = virtualInstance.Name
local unappliedProperties = {}
for propertyName, virtualValue in pairs(virtualInstance.Properties) do
if next(virtualValue) == "Ref" then
table.insert(deferredRefs, {
id = id,
instance = instance,
propertyName = propertyName,
virtualValue = virtualValue,
})
continue
end
local decodeSuccess, value = decodeValue(virtualValue, instanceMap)
if not decodeSuccess then
unappliedProperties[propertyName] = virtualValue
continue
end
local setPropertySuccess = setProperty(instance, propertyName, value)
if not setPropertySuccess then
unappliedProperties[propertyName] = virtualValue
end
end
if next(unappliedProperties) ~= nil then
table.insert(unappliedPatch.updated, {
id = id,
changedProperties = unappliedProperties,
})
end
for _, childId in ipairs(virtualInstance.Children) do
reifyInstanceInner(unappliedPatch, deferredRefs, instanceMap, virtualInstances, childId, instance)
end
instance.Parent = parentInstance
instanceMap:insert(id, instance)
end
function applyDeferredRefs(instanceMap, deferredRefs, unappliedPatch)
local function markFailed(id, propertyName, virtualValue)
for _, existingUpdate in ipairs(unappliedPatch.updated) do
if existingUpdate.id == id then
existingUpdate.changedProperties[propertyName] = virtualValue
return
end
end
table.insert(unappliedPatch.updated, {
id = id,
changedProperties = {
[propertyName] = virtualValue,
},
})
end
for _, entry in ipairs(deferredRefs) do
local _, refId = next(entry.virtualValue)
if refId == nil then
continue
end
local targetInstance = instanceMap.fromIds[refId]
if targetInstance == nil then
markFailed(entry.id, entry.propertyName, entry.virtualValue)
continue
end
local setPropertySuccess = setProperty(entry.instance, entry.propertyName, targetInstance)
if not setPropertySuccess then
markFailed(entry.id, entry.propertyName, entry.virtualValue)
end
end
end
return {
reifyInstance = reifyInstance,
applyDeferredRefs = applyDeferredRefs,
}