public override string ToString()
        {
            string pathToDesriptor          = string.Empty;
            PersistentDescriptor descriptor = this;

            if (descriptor.Parent == null)
            {
                pathToDesriptor += "/";
            }
            else
            {
                while (descriptor.Parent != null)
                {
                    pathToDesriptor += "/" + descriptor.Parent.PersistentID;
                    descriptor       = descriptor.Parent;
                }
            }
            return(string.Format("Descriptor InstanceId = {0}, Type = {1}, Path = {2}, Children = {3} Components = {4}", PersistentID, PersistentTypeGuid, pathToDesriptor, Children != null ? Children.Length : 0, Components != null ? Components.Length : 0));
        }
        protected override object WriteToImpl(object obj)
        {
            if (Descriptors == null && Data == null)
            {
                return(obj);
            }

            if (Descriptors == null && Data != null || Data != null && Descriptors == null)
            {
                throw new ArgumentException("data is corrupted", "scene");
            }

            if (Descriptors.Length == 0)
            {
                return(obj);
            }

            if (Identifiers == null || Identifiers.Length != Data.Length)
            {
                throw new ArgumentException("data is corrupted", "scene");
            }

            Scene scene = (Scene)obj;

            GameObject[] rootGameObjects = scene.GetRootGameObjects();
            for (int i = 0; i < rootGameObjects.Length; ++i)
            {
                GameObject rootGO = rootGameObjects[i];
                if (rootGO.GetComponent <RTSLIgnore>())
                {
                    continue;
                }

                UnityObject.DestroyImmediate(rootGO);
            }

            Dictionary <int, UnityObject> idToUnityObj = new Dictionary <int, UnityObject>();

            for (int i = 0; i < Descriptors.Length; ++i)
            {
                PersistentDescriptor descriptor = Descriptors[i];
                if (descriptor != null)
                {
                    CreateGameObjectWithComponents(m_typeMap, descriptor, idToUnityObj, null);
                }
            }


            UnityObject[] assetInstances = null;
            if (AssetIdentifiers != null)
            {
                IUnityObjectFactory factory = IOC.Resolve <IUnityObjectFactory>();
                assetInstances = new UnityObject[AssetIdentifiers.Length];
                for (int i = 0; i < AssetIdentifiers.Length; ++i)
                {
                    PersistentObject asset = Assets[i];

                    Type uoType = m_typeMap.ToUnityType(asset.GetType());
                    if (uoType != null)
                    {
                        if (factory.CanCreateInstance(uoType, asset))
                        {
                            UnityObject assetInstance = factory.CreateInstance(uoType, asset);
                            if (assetInstance != null)
                            {
                                assetInstances[i] = assetInstance;
                                idToUnityObj.Add(AssetIdentifiers[i], assetInstance);
                            }
                        }
                        else
                        {
                            Debug.LogWarning("Unable to create object of type " + uoType.ToString());
                        }
                    }
                    else
                    {
                        Debug.LogWarning("Unable to resolve unity type for " + asset.GetType().FullName);
                    }
                }
            }

            m_assetDB.RegisterSceneObjects(idToUnityObj);

            if (assetInstances != null)
            {
                for (int i = 0; i < AssetIdentifiers.Length; ++i)
                {
                    UnityObject assetInstance = assetInstances[i];
                    if (assetInstance != null)
                    {
                        PersistentObject asset = Assets[i];
                        asset.WriteTo(assetInstance);
                    }
                }
            }

            RestoreDataAndResolveDependencies();
            m_assetDB.UnregisterSceneObjects();

            return(scene);
        }
        protected override void ReadFromImpl(object obj)
        {
            Scene scene = (Scene)obj;

            GameObject[] rootGameObjects = scene.GetRootGameObjects();

            List <PersistentObject>     data            = new List <PersistentObject>();
            List <long>                 identifiers     = new List <long>();
            List <PersistentDescriptor> descriptors     = new List <PersistentDescriptor>(rootGameObjects.Length);
            GetDepsFromContext          getSceneDepsCtx = new GetDepsFromContext();

            for (int i = 0; i < rootGameObjects.Length; ++i)
            {
                GameObject           rootGO     = rootGameObjects[i];
                PersistentDescriptor descriptor = CreateDescriptorAndData(rootGO, data, identifiers, getSceneDepsCtx);
                if (descriptor != null)
                {
                    descriptors.Add(descriptor);
                }
            }

            HashSet <object>    allDeps      = getSceneDepsCtx.Dependencies;
            List <UnityObject>  externalDeps = new List <UnityObject>(allDeps.OfType <UnityObject>());
            Queue <UnityObject> depsQueue    = new Queue <UnityObject>(allDeps.OfType <UnityObject>());

            List <PersistentObject> assets = new List <PersistentObject>();
            List <int> assetIdentifiers    = new List <int>();

            GetDepsFromContext getDepsCtx = new GetDepsFromContext();

            while (depsQueue.Count > 0)
            {
                UnityObject uo = depsQueue.Dequeue();
                if (!uo)
                {
                    continue;
                }
                if (!m_assetDB.IsMapped(uo))
                {
                    if (!(uo is GameObject) && !(uo is Component))
                    {
                        Type persistentType = m_typeMap.ToPersistentType(uo.GetType());
                        if (persistentType != null)
                        {
                            getDepsCtx.Clear();

                            PersistentObject persistentObject = (PersistentObject)Activator.CreateInstance(persistentType);
                            persistentObject.ReadFrom(uo);
                            persistentObject.GetDepsFrom(uo, getDepsCtx);

                            assets.Add(persistentObject);
                            assetIdentifiers.Add(uo.GetInstanceID());

                            foreach (UnityObject dep in getDepsCtx.Dependencies)
                            {
                                if (!allDeps.Contains(dep))
                                {
                                    allDeps.Add(dep);
                                    depsQueue.Enqueue(dep);
                                }
                            }
                        }
                    }
                    externalDeps.Remove(uo);
                }
            }

            Descriptors  = descriptors.ToArray();
            Identifiers  = identifiers.ToArray();
            Data         = data.ToArray();
            Dependencies = externalDeps.Select(uo => m_assetDB.ToID(uo)).ToArray();

            Assets           = assets.ToArray();
            AssetIdentifiers = assetIdentifiers.ToArray();
        }
        protected PersistentDescriptor CreateDescriptorAndData(GameObject go, List <PersistentObject> persistentData, List <long> persistentIdentifiers, /*HashSet<int> usings,*/ GetDepsFromContext getDepsFromCtx, PersistentDescriptor parentDescriptor = null)
        {
            if (go.GetComponent <RTSLIgnore>())
            {
                //Do not save persistent ignore objects
                return(null);
            }
            Type persistentType = m_typeMap.ToPersistentType(go.GetType());

            if (persistentType == null)
            {
                return(null);
            }

            long persistentID = ToID(go);
            //if(m_assetDB.IsResourceID(persistentID))
            //{
            //    int ordinal = m_assetDB.ToOrdinal(persistentID);
            //    usings.Add(ordinal);
            //}

            PersistentDescriptor descriptor = new PersistentDescriptor(m_typeMap.ToGuid(persistentType), persistentID, go.name);

            descriptor.Parent = parentDescriptor;

            PersistentObject goData = (PersistentObject)Activator.CreateInstance(persistentType);

            goData.ReadFrom(go);
            goData.GetDepsFrom(go, getDepsFromCtx);
            persistentData.Add(goData);
            persistentIdentifiers.Add(persistentID);

            Component[] components = go.GetComponents <Component>().Where(c => c != null).ToArray();
            if (components.Length > 0)
            {
                List <PersistentDescriptor> componentDescriptors = new List <PersistentDescriptor>();
                for (int i = 0; i < components.Length; ++i)
                {
                    Component component = components[i];
                    Type      persistentComponentType = m_typeMap.ToPersistentType(component.GetType());
                    if (persistentComponentType == null)
                    {
                        continue;
                    }

                    long componentID = ToID(component);
                    //if (m_assetDB.IsResourceID(componentID))
                    //{
                    //    int ordinal = m_assetDB.ToOrdinal(componentID);
                    //    usings.Add(ordinal);
                    //}
                    PersistentDescriptor componentDescriptor = new PersistentDescriptor(m_typeMap.ToGuid(persistentComponentType), componentID, component.name);
                    componentDescriptor.Parent = descriptor;
                    componentDescriptors.Add(componentDescriptor);

                    PersistentObject componentData = (PersistentObject)Activator.CreateInstance(persistentComponentType);
                    componentData.ReadFrom(component);
                    componentData.GetDepsFrom(component, getDepsFromCtx);
                    persistentData.Add(componentData);
                    persistentIdentifiers.Add(componentID);
                }

                if (componentDescriptors.Count > 0)
                {
                    descriptor.Components = componentDescriptors.ToArray();
                }
            }

            Transform transform = go.transform;

            if (transform.childCount > 0)
            {
                List <PersistentDescriptor> children = new List <PersistentDescriptor>();
                foreach (Transform child in transform)
                {
                    PersistentDescriptor childDescriptor = CreateDescriptorAndData(child.gameObject, persistentData, persistentIdentifiers, /*usings,*/ getDepsFromCtx, descriptor);
                    if (childDescriptor != null)
                    {
                        children.Add(childDescriptor);
                    }
                }

                descriptor.Children = children.ToArray();
            }

            return(descriptor);
        }
        private UnityObject AddComponent(Dictionary <int, UnityObject> idToObj, GameObject go, Dictionary <Type, bool> requirements, PersistentDescriptor componentDescriptor, Type componentType)
        {
            Component component;
            bool      isReqFulfilled             = requirements.ContainsKey(componentType) && requirements[componentType];
            bool      maybeComponentAlreadyAdded =
                !isReqFulfilled ||
                componentType.IsSubclassOf(typeof(Transform)) ||
                componentType == typeof(Transform) ||
                componentType.IsDefined(typeof(DisallowMultipleComponent), true) ||
                ComponentDependencies.ContainsKey(componentType) && ComponentDependencies[componentType].Any(d => go.GetComponent(d) != null);

            if (maybeComponentAlreadyAdded)
            {
                component = go.GetComponent(componentType);
                if (component == null)
                {
                    component = go.AddComponent(componentType);
                }
                if (!isReqFulfilled)
                {
                    requirements[componentType] = true;
                }
            }
            else
            {
                component = go.AddComponent(componentType);
                if (component == null)
                {
                    component = go.GetComponent(componentType);
                }
            }
            if (component == null)
            {
                Debug.LogErrorFormat("Unable to add or get component of type {0}", componentType);
            }
            else
            {
                object[] requireComponents = component.GetType().GetCustomAttributes(typeof(RequireComponent), true);
                for (int j = 0; j < requireComponents.Length; ++j)
                {
                    RequireComponent requireComponent = requireComponents[j] as RequireComponent;
                    if (requireComponent != null)
                    {
                        if (requireComponent.m_Type0 != null && !requirements.ContainsKey(requireComponent.m_Type0))
                        {
                            bool fulfilled = go.GetComponent(requireComponent.m_Type0);
                            requirements.Add(requireComponent.m_Type0, fulfilled);
                        }
                        if (requireComponent.m_Type1 != null && !requirements.ContainsKey(requireComponent.m_Type1))
                        {
                            bool fulfilled = go.GetComponent(requireComponent.m_Type1);
                            requirements.Add(requireComponent.m_Type1, fulfilled);
                        }
                        if (requireComponent.m_Type2 != null && !requirements.ContainsKey(requireComponent.m_Type2))
                        {
                            bool fulfilled = go.GetComponent(requireComponent.m_Type2);
                            requirements.Add(requireComponent.m_Type2, fulfilled);
                        }
                    }
                }
                idToObj.Add(m_assetDB.ToInt(componentDescriptor.PersistentID), component);
            }

            return(component);
        }
        /// <summary>
        /// Create GameObjects hierarchy and Add Components recursively
        /// </summary>
        /// <param name="descriptor">PersistentObject descriptor (initially root descriptor)</param>
        /// <param name="idToObj">Dictionary instanceId->UnityObject which will be populated with GameObjects and Components</param>
        public void CreateGameObjectWithComponents(ITypeMap typeMap, PersistentDescriptor descriptor, Dictionary <int, UnityObject> idToObj, Transform parent, List <GameObject> createdGameObjects = null, Dictionary <long, UnityObject> decomposition = null)
        {
            UnityObject objGo;
            GameObject  go;

            if (idToObj.TryGetValue(m_assetDB.ToInt(descriptor.PersistentID), out objGo))
            {
                throw new ArgumentException(string.Format("duplicate object descriptor found in descriptors hierarchy. {0}", descriptor.ToString()), "descriptor");
            }
            else
            {
                go = new GameObject();
                if (parent != null)
                {
                    go.transform.SetParent(parent, false);
                }
                idToObj.Add(m_assetDB.ToInt(descriptor.PersistentID), go);
            }

            if (decomposition != null)
            {
                if (!decomposition.ContainsKey(descriptor.PersistentID))
                {
                    decomposition.Add(descriptor.PersistentID, go);
                }
            }

            if (createdGameObjects != null)
            {
                createdGameObjects.Add(go);
            }

            go.SetActive(false);

            if (descriptor.Parent != null)
            {
                UnityObject parentGO;
                if (!idToObj.TryGetValue(m_assetDB.ToInt(descriptor.Parent.PersistentID), out parentGO))
                {
                    throw new ArgumentException(string.Format("objects dictionary is supposed to have object with PersistentID {0} at this stage. Descriptor {1}", descriptor.Parent.PersistentID, descriptor, "descriptor"));
                }

                if (parentGO == null)
                {
                    throw new ArgumentException(string.Format("object with PersistentID {0} should have GameObject type. Descriptor {1}", descriptor.Parent.PersistentID, descriptor, "descriptor"));
                }
                go.transform.SetParent(((GameObject)parentGO).transform, false);
            }

            if (descriptor.Components != null)
            {
                Dictionary <Type, bool> requirements = new Dictionary <Type, bool>();
                for (int i = 0; i < descriptor.Components.Length; ++i)
                {
                    PersistentDescriptor componentDescriptor = descriptor.Components[i];

                    Type persistentComponentType = m_typeMap.ToType(componentDescriptor.PersistentTypeGuid);
                    if (persistentComponentType == null)
                    {
                        Debug.LogWarningFormat("Unknown type {0} associated with component Descriptor {1}", componentDescriptor.PersistentTypeGuid, componentDescriptor.ToString());
                        idToObj.Add(m_assetDB.ToInt(componentDescriptor.PersistentID), null);
                        continue;
                    }
                    Type componentType = typeMap.ToUnityType(persistentComponentType);
                    if (componentType == null)
                    {
                        Debug.LogWarningFormat("There is no mapped type for " + persistentComponentType.FullName + " in TypeMap");
                        idToObj.Add(m_assetDB.ToInt(componentDescriptor.PersistentID), null);
                        continue;
                    }

                    if (!componentType.IsSubclassOf(typeof(Component)))
                    {
                        Debug.LogErrorFormat("{0} is not subclass of {1}", componentType.FullName, typeof(Component).FullName);
                        idToObj.Add(m_assetDB.ToInt(componentDescriptor.PersistentID), null);
                        continue;
                    }

                    UnityObject obj;
                    if (idToObj.TryGetValue(m_assetDB.ToInt(componentDescriptor.PersistentID), out obj))
                    {
                        if (obj != null && !(obj is Component))
                        {
                            Debug.LogError("Invalid Type. Component " + obj.name + " " + obj.GetType() + " " + obj.GetInstanceID() + " " + descriptor.PersistentTypeGuid + " " + componentDescriptor.PersistentTypeGuid);
                        }
                    }
                    else
                    {
                        obj = AddComponent(idToObj, go, requirements, componentDescriptor, componentType);
                    }

                    if (decomposition != null)
                    {
                        if (!decomposition.ContainsKey(componentDescriptor.PersistentID))
                        {
                            decomposition.Add(componentDescriptor.PersistentID, obj);
                        }
                    }
                }
            }

            if (descriptor.Children != null)
            {
                for (int i = 0; i < descriptor.Children.Length; ++i)
                {
                    PersistentDescriptor childDescriptor = descriptor.Children[i];
                    CreateGameObjectWithComponents(typeMap, childDescriptor, idToObj, null, createdGameObjects, decomposition);
                }
            }
        }