in MREUnityRuntimeLib/App/MixedRealityExtensionApp.cs [972:1086]
private void ProcessCreatedActors(CreateActor originalMessage, IList<Actor> createdActors, Action onCompleteCallback, string guidSeed = null)
{
Guid guidGenSeed;
if (originalMessage != null)
{
guidGenSeed = originalMessage.Actor.Id;
}
else
{
guidGenSeed = UtilMethods.StringToGuid(guidSeed);
}
var guids = new DeterministicGuids(guidGenSeed);
// find the actors with no actor parents
var rootActors = GetDistinctTreeRoots(
createdActors.Select(a => a.gameObject).ToArray()
).Select(go => go.GetComponent<Actor>()).ToArray();
var rootActor = createdActors.FirstOrDefault();
var createdAnims = new List<Animation.BaseAnimation>(5);
if (rootActors.Length == 1 && rootActor.transform.parent == null)
{
// Delete entire hierarchy as we no longer have a valid parent actor for the root of this hierarchy. It was likely
// destroyed in the process of the async operation before this callback was called.
foreach (var actor in createdActors)
{
actor.Destroy();
}
createdActors.Clear();
SendCreateActorResponse(
originalMessage,
failureMessage: "Parent for the actor being created no longer exists. Cannot create new actor.");
return;
}
var secondPassXfrms = new List<Transform>(2);
foreach (var root in rootActors)
{
ProcessActors(root.transform, root.transform.parent != null ? root.transform.parent.GetComponent<Actor>() : null);
}
// some things require the whole hierarchy to have actors on it. run those here
foreach (var pass2 in secondPassXfrms)
{
ProcessActors2(pass2);
}
if (originalMessage != null && rootActors.Length == 1)
{
rootActor?.ApplyPatch(originalMessage.Actor);
}
Actor.ApplyVisibilityUpdate(rootActor);
_actorManager.UponStable(
() => SendCreateActorResponse(originalMessage, actors: createdActors, anims: createdAnims, onCompleteCallback: onCompleteCallback));
void ProcessActors(Transform xfrm, Actor parent)
{
// Generate actors for all GameObjects, even if the loader didn't. Only loader-generated
// actors are returned to the app though. We do this so library objects get enabled/disabled
// correctly, even if they're not tracked by the app.
var actor = xfrm.gameObject.GetComponent<Actor>() ?? xfrm.gameObject.AddComponent<Actor>();
_actorManager.AddActor(guids.Next(), actor);
_ownedGameObjects.Add(actor.gameObject);
actor.ParentId = parent?.Id ?? actor.ParentId;
if (actor.Renderer != null)
{
// only overwrite material if there's something in the cache, i.e. not a random library material
var matId = AssetManager.GetByObject(actor.Renderer.sharedMaterial)?.Id;
if (matId.HasValue)
{
actor.MaterialId = matId.Value;
}
actor.MeshId = AssetManager.GetByObject(actor.UnityMesh)?.Id ?? Guid.Empty;
}
// native animation construction requires the whole actor hierarchy to already exist. defer to second pass
var nativeAnim = xfrm.gameObject.GetComponent<UnityEngine.Animation>();
if (nativeAnim != null && createdActors.Contains(actor))
{
secondPassXfrms.Add(xfrm);
}
foreach (Transform child in xfrm)
{
ProcessActors(child, actor);
}
}
void ProcessActors2(Transform xfrm)
{
var actor = xfrm.gameObject.GetComponent<Actor>();
var nativeAnim = xfrm.gameObject.GetComponent<UnityEngine.Animation>();
if (nativeAnim != null && createdActors.Contains(actor))
{
var animTargets = xfrm.gameObject.GetComponent<PrefabAnimationTargets>();
int stateIndex = 0;
foreach (AnimationState state in nativeAnim)
{
var anim = new NativeAnimation(AnimationManager, guids.Next(), nativeAnim, state);
anim.TargetIds = animTargets != null
? animTargets.GetTargets(xfrm, stateIndex++, addRootToTargets: true).Select(a => a.Id).ToList()
: new List<Guid>() { actor.Id };
AnimationManager.RegisterAnimation(anim);
createdAnims.Add(anim);
}
}
}
}