mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 22:11:38 +00:00
RunContext refactor + sync updates
This commit is contained in:
parent
c7cddb72c2
commit
d3cc11659a
79 changed files with 1415 additions and 626 deletions
|
|
@ -8,6 +8,12 @@
|
|||
- All other instances -> .model.json files or directories
|
||||
|
||||
Children are recursively encoded and included.
|
||||
|
||||
DUPLICATE HANDLING:
|
||||
- Instances with duplicate-named siblings at ANY level of the path are skipped
|
||||
- This matches the behavior in ref_properties.rs::is_path_unique
|
||||
- A path is ambiguous if duplicates exist anywhere from the instance to the root
|
||||
- A warning is logged when duplicates are encountered
|
||||
]]
|
||||
|
||||
local Packages = script.Parent.Parent.Parent.Packages
|
||||
|
|
@ -41,9 +47,65 @@ local DIRECTORY_CLASSES = {
|
|||
AdGui = true,
|
||||
}
|
||||
|
||||
-- Finds duplicate names among a list of instances
|
||||
-- Returns a set of names that appear more than once
|
||||
local function findDuplicateNames(children: { Instance }): { [string]: boolean }
|
||||
local nameCounts: { [string]: number } = {}
|
||||
local duplicates: { [string]: boolean } = {}
|
||||
|
||||
for _, child in children do
|
||||
local name = child.Name
|
||||
nameCounts[name] = (nameCounts[name] or 0) + 1
|
||||
if nameCounts[name] > 1 then
|
||||
duplicates[name] = true
|
||||
end
|
||||
end
|
||||
|
||||
return duplicates
|
||||
end
|
||||
|
||||
-- Checks if an instance has duplicate-named siblings
|
||||
local function hasDuplicateSiblings(instance: Instance): boolean
|
||||
local parent = instance.Parent
|
||||
if not parent then
|
||||
return false
|
||||
end
|
||||
|
||||
local siblings = parent:GetChildren()
|
||||
local duplicates = findDuplicateNames(siblings)
|
||||
return duplicates[instance.Name] == true
|
||||
end
|
||||
|
||||
-- Checks if the path to an instance is unique by walking up the tree.
|
||||
-- Returns false if ANY ancestor (including the instance itself) has duplicate siblings.
|
||||
-- This matches the behavior of is_path_unique in ref_properties.rs
|
||||
local function isPathUnique(instance: Instance): boolean
|
||||
local current = instance
|
||||
|
||||
while current do
|
||||
-- Check if current has duplicate-named siblings
|
||||
if hasDuplicateSiblings(current) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Move up to parent
|
||||
current = current.Parent
|
||||
|
||||
-- Stop at game (DataModel) - we've reached the root
|
||||
if current and current == game then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Forward declaration for recursion
|
||||
local encodeInstance
|
||||
|
||||
-- Track skipped duplicates for logging
|
||||
local skippedDuplicateCount = 0
|
||||
|
||||
-- Encode Attributes if present on any instance
|
||||
local function encodeAttributes(instance, properties)
|
||||
-- Try to get Attributes - this works for all instance types
|
||||
|
|
@ -64,7 +126,21 @@ local function encodeAttributes(instance, properties)
|
|||
end
|
||||
end
|
||||
|
||||
encodeInstance = function(instance, parentId)
|
||||
encodeInstance = function(instance, parentId, _skipPathCheck)
|
||||
-- Check if the entire path to this instance is unique (unless we're in a recursive call)
|
||||
-- For top-level instances, we check the entire ancestor chain for duplicates
|
||||
-- For children, the parent already verified the path is unique up to that point,
|
||||
-- so we only need to check siblings at each level (done in the recursion below)
|
||||
if not _skipPathCheck and not isPathUnique(instance) then
|
||||
skippedDuplicateCount += 1
|
||||
Log.warn(
|
||||
"Skipped instance '{}' ({}) - path contains duplicate-named siblings (cannot reliably sync)",
|
||||
instance:GetFullName(),
|
||||
instance.ClassName
|
||||
)
|
||||
return nil
|
||||
end
|
||||
|
||||
local properties = {}
|
||||
|
||||
-- Always try to encode Attributes for any instance type
|
||||
|
|
@ -111,10 +187,25 @@ encodeInstance = function(instance, parentId)
|
|||
end
|
||||
-- For directory classes (Folder, Configuration, etc.), we only encode Attributes (done above)
|
||||
|
||||
-- Recursively encode children
|
||||
-- Recursively encode children, skipping those with duplicate names
|
||||
local children = {}
|
||||
for _, child in ipairs(instance:GetChildren()) do
|
||||
local encodedChild = encodeInstance(child, nil) -- parentId will be resolved server-side
|
||||
local childInstances = instance:GetChildren()
|
||||
local childDuplicates = findDuplicateNames(childInstances)
|
||||
|
||||
for _, child in ipairs(childInstances) do
|
||||
-- Skip children with duplicate names
|
||||
if childDuplicates[child.Name] then
|
||||
skippedDuplicateCount += 1
|
||||
Log.warn(
|
||||
"Skipped child instance '{}' ({}) - has duplicate-named siblings (cannot reliably sync)",
|
||||
child:GetFullName(),
|
||||
child.ClassName
|
||||
)
|
||||
continue
|
||||
end
|
||||
|
||||
-- Pass true to skip duplicate check since we already checked above
|
||||
local encodedChild = encodeInstance(child, nil, true)
|
||||
if encodedChild then
|
||||
table.insert(children, encodedChild)
|
||||
end
|
||||
|
|
@ -129,4 +220,20 @@ encodeInstance = function(instance, parentId)
|
|||
}
|
||||
end
|
||||
|
||||
return encodeInstance
|
||||
-- Wrapper function that resets the duplicate count and returns the final count
|
||||
local function encodeInstanceWithDuplicateTracking(instance, parentId)
|
||||
skippedDuplicateCount = 0
|
||||
local result = encodeInstance(instance, parentId, false)
|
||||
|
||||
-- Log summary if any duplicates were skipped
|
||||
if skippedDuplicateCount > 0 then
|
||||
Log.warn(
|
||||
"Skipped {} location(s) with duplicate-named siblings during pull (cannot reliably sync)",
|
||||
skippedDuplicateCount
|
||||
)
|
||||
end
|
||||
|
||||
return result, skippedDuplicateCount
|
||||
end
|
||||
|
||||
return encodeInstanceWithDuplicateTracking
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue