diff --git a/Runtime/Scripts/BaseMeshSync.cs b/Runtime/Scripts/BaseMeshSync.cs index dc4a453ce..c36b8a6d2 100644 --- a/Runtime/Scripts/BaseMeshSync.cs +++ b/Runtime/Scripts/BaseMeshSync.cs @@ -1746,13 +1746,98 @@ private EntityRecord UpdatePointsEntity(PointsData data, MeshSyncPlayerConfig co return rec; } + static Transform FindOrCreateByPath(Transform parent, string path, Action parentCreationCallback, bool worldPositionStays = true) { + string[] names = path.Split('/'); + if (names.Length <= 0) + return null; + + //if parent is null, search from root + Transform t = parent; + int tokenStartIdx = 0; + if (null == t) { + string rootGameObjectName = names[0]; + t = FilmInternalUtilities.GameObjectUtility.FindFirstRoot(rootGameObjectName); + if (null == t) { + GameObject go = new GameObject(rootGameObjectName); + t = go.GetComponent(); + } + + tokenStartIdx = 1; + } + + static Transform FindOrCreateChild(Transform t, string childName, out bool didCreate, bool worldPositionStays = true) { + Transform childT = t.Find(childName); + if (null != childT) { + didCreate = false; + return childT; + } + + GameObject go = new GameObject(childName); + childT = go.transform; + childT.SetParent(t, worldPositionStays); + didCreate = true; + return childT; + } + + //loop over hierarchy of names and generate parents that don't exist + int nameLength = names.Length; + List processedParents = new List(); + for (int i = tokenStartIdx; i < nameLength; ++i) { + string nameToken = names[i]; + if (string.IsNullOrEmpty(nameToken)) + continue; + + processedParents.Add(nameToken); + + t = FindOrCreateChild(t, nameToken, out var didCreate, worldPositionStays); + if (i < nameLength - 1 && didCreate) { + var parentPath = String.Join("/", processedParents); + if (!parentPath.StartsWith("/")) { + parentPath = $"/{parentPath}"; + } + + parentCreationCallback?.Invoke(parentPath); + } + + if (null == t) + return null; + } + + return t; + } + + void AddClientObject(string path, out EntityRecord rec) { + if (m_clientObjects.TryGetValue(path, out rec)) + if (rec.go == null) { + m_clientObjects.Remove(path); + rec = null; + } + + if (rec == null) { + var trans = FindOrCreateByPath(m_rootObject, path, + delegate(string parentPath) { + EntityRecord parentRec = null; + AddClientObject(parentPath, out parentRec); + if (parentRec.dataType == EntityType.Unknown) + parentRec.dataType = EntityType.Transform; + }, + false); + + rec = new EntityRecord { + go = trans.gameObject, + trans = trans, + recved = true + }; + m_clientObjects.Add(path, rec); + } + } + private EntityRecord UpdateTransformEntity(TransformData data, MeshSyncPlayerConfig config) { string path = data.path; int hostID = data.hostID; if (path.Length == 0) return null; - Transform trans = null; EntityRecord rec = null; if (hostID != Lib.invalidID) { if (m_hostObjects.TryGetValue(hostID, out rec)) @@ -1765,21 +1850,7 @@ private EntityRecord UpdateTransformEntity(TransformData data, MeshSyncPlayerCon return null; } else { - if (m_clientObjects.TryGetValue(path, out rec)) - if (rec.go == null) { - m_clientObjects.Remove(path); - rec = null; - } - - if (rec == null) { - trans = FilmInternalUtilities.GameObjectUtility.FindOrCreateByPath(m_rootObject, path, false); - rec = new EntityRecord { - go = trans.gameObject, - trans = trans, - recved = true - }; - m_clientObjects.Add(path, rec); - } + AddClientObject(path, out rec); } return UpdateTransformEntity(data, config, rec);