예제 #1
0
        private static void UpdateReferences(SessionViewModel session)
        {
            if (session == null)
            {
                throw new ArgumentNullException(nameof(session));
            }

            var dirtyReferencers      = new HashSet <AssetViewModel>();
            var dirtyAssets           = new HashSet <AssetViewModel>();
            var dirtyReferenced       = new HashSet <AssetViewModel>();
            var dirtyDirectReferenced = new HashSet <AssetViewModel>();
            var referencerAssets      = new HashSet <AssetViewModel>();
            var referencedAssets      = new HashSet <AssetViewModel>();
            TaskCompletionSource <int> tcs;

            lock (DirtyDependencies)
            {
                foreach (var asset in DirtyDependencies)
                {
                    // Add dirty dependencies from the previous reference values
                    dirtyReferencers.AddRange(asset.Dependencies.RecursiveReferencerAssets);
                    dirtyReferenced.AddRange(asset.Dependencies.RecursiveReferencedAssets);
                    dirtyDirectReferenced.AddRange(asset.Dependencies.ReferencedAssets);

                    referencerAssets.Clear();
                    referencedAssets.Clear();

                    if (!asset.IsDeleted)
                    {
                        var dependencyManager = session.DependencyManager;
                        var dependencies      = dependencyManager.ComputeDependencies(asset.AssetItem.Id, AssetDependencySearchOptions.In | AssetDependencySearchOptions.Out, ContentLinkType.Reference); // TODO: Change ContentLinkType.Reference to handle other types
                        if (dependencies != null)
                        {
                            dependencies.LinksIn.Select(x => session.GetAssetById(x.Item.Id)).NotNull().ForEach(x => referencerAssets.Add(x));
                            dependencies.LinksOut.Select(x => session.GetAssetById(x.Item.Id)).NotNull().ForEach(x => referencedAssets.Add(x));
                        }
                        dirtyAssets.Add(asset);

                        // Add dirty dependencies from the updated reference values
                        dirtyReferencers.AddRange(referencerAssets);
                        dirtyReferenced.AddRange(referencedAssets);
                        dirtyDirectReferenced.AddRange(referencedAssets);
                    }

                    // Note: the collections can be empty. This is especially needed when reimporting - we want to be sure that references are cleared.
                    asset.Dependencies.ReferencerAssets = referencerAssets.ToList();
                    asset.Dependencies.ReferencedAssets = referencedAssets.ToList();
                }
                DirtyDependencies.Clear();

                // Clear the task now that we processed all the dirty dependencies
                tcs = dependenciesUpdated;
                dependenciesUpdated = null;
            }

            dirtyDirectReferenced.ExceptWith(dirtyAssets);
            // Add the dirty assets to the list of asset that needs to update recursive referenced assets.
            dirtyReferencers.AddRange(dirtyAssets);
            // Imported/undeleted assets must update their recursive referencers
            dirtyReferenced.AddRange(dirtyAssets);

            // Update the referencers of the (previous/updated) directly referenced assets
            foreach (var asset in dirtyDirectReferenced)
            {
                var dependencyManager = session.DependencyManager;
                var dependencies      = dependencyManager.ComputeDependencies(asset.AssetItem.Id, AssetDependencySearchOptions.In, ContentLinkType.Reference); // TODO: Change ContentLinkType.Reference to handle other types
                referencerAssets.Clear();
                dependencies?.LinksIn.Select(x => session.GetAssetById(x.Item.Id)).NotNull().ForEach(x => referencerAssets.Add(x));
                asset.Dependencies.ReferencerAssets = referencerAssets.ToList();
            }

            // Update recursive lists of referenced/referenced assets for assets affected by the changes
            foreach (var asset in dirtyReferenced)
            {
                asset.Dependencies.OnPropertyChanging(nameof(IsIndirectlyIncluded), nameof(IsExcluded));
                asset.Dependencies.UpdateRecursiveReferencerAssets();
                asset.Dependencies.OnPropertyChanged(nameof(IsIndirectlyIncluded), nameof(IsExcluded));
            }
            foreach (var asset in dirtyReferencers)
            {
                asset.Dependencies.UpdateRecursiveReferencedAssets();
            }
            foreach (var asset in dirtyAssets)
            {
                asset.Dependencies.OnPropertyChanging(nameof(IsIndirectlyIncluded), nameof(IsExcluded));
                asset.Dependencies.OnPropertyChanged(nameof(IsIndirectlyIncluded), nameof(IsExcluded));
            }

            // Job is completed, notify anything awaiting on it
            tcs.SetResult(0);
        }
예제 #2
0
        private async void OpenDefaultScene(SessionViewModel session)
        {
            var startupPackage = session.LocalPackages.OfType <ProjectViewModel>().SingleOrDefault(x => x.IsCurrentProject);

            if (startupPackage == null)
            {
                return;
            }

            var gameSettingsAsset = startupPackage.Assets.FirstOrDefault(x => x.Url == Assets.GameSettingsAsset.GameSettingsLocation);

            if (gameSettingsAsset == null)
            {
                // Scan dependencies for game settings
                // TODO: Scanning order? (direct dependencies first)
                // TODO: Switch to using startupPackage.Dependencies view model instead
                foreach (var dependency in startupPackage.PackageContainer.FlattenedDependencies)
                {
                    if (dependency.Package == null)
                    {
                        continue;
                    }

                    var dependencyPackageViewModel = session.AllPackages.First(x => x.Package == dependency.Package);
                    if (dependencyPackageViewModel == null)
                    {
                        continue;
                    }

                    gameSettingsAsset = dependencyPackageViewModel.Assets.FirstOrDefault(x => x.Url == Assets.GameSettingsAsset.GameSettingsLocation);
                    if (gameSettingsAsset != null)
                    {
                        break;
                    }
                }
            }

            if (gameSettingsAsset == null)
            {
                return;
            }

            var defaultScene = ((Assets.GameSettingsAsset)gameSettingsAsset?.Asset)?.DefaultScene;

            if (defaultScene == null)
            {
                return;
            }

            var defaultSceneReference = AttachedReferenceManager.GetAttachedReference(defaultScene);

            if (defaultSceneReference == null)
            {
                return;
            }

            var asset = session.GetAssetById(defaultSceneReference.Id);

            if (asset == null)
            {
                return;
            }

            Editor.Session.ActiveAssetView.SelectAssets(asset.Yield());

            await assetEditorsManager.OpenAssetEditorWindow(asset);
        }
        private async Task PullSourceFileChanges()
        {
            var sourceTracker     = session.SourceTracker;
            var bufferBlock       = new BufferBlock <IReadOnlyList <SourceFileChangedData> >();
            var changedAssets     = new HashSet <AssetViewModel>();
            var sourceFileChanges = new List <SourceFileChangedData>();

            using (sourceTracker.SourceFileChanged.LinkTo(bufferBlock))
            {
                sourceTracker.EnableTracking = true;
                while (!IsDestroyed)
                {
                    // Await for source file changes
                    await bufferBlock.OutputAvailableAsync(cancel.Token);

                    if (cancel.IsCancellationRequested)
                    {
                        return;
                    }

                    // Try as much as possible to process all changes at once
                    IList <IReadOnlyList <SourceFileChangedData> > changes;
                    bufferBlock.TryReceiveAll(out changes);
                    sourceFileChanges.AddRange(changes.SelectMany(x => x));

                    if (sourceFileChanges.Count == 0)
                    {
                        continue;
                    }

                    for (var i = 0; i < sourceFileChanges.Count; i++)
                    {
                        var sourceFileChange = sourceFileChanges[i];
                        // Look first in the assets of the session, then in the list of deleted assets.
                        var asset = sessionViewModel.GetAssetById(sourceFileChange.AssetId)
                                    ?? sessionViewModel.AllPackages.SelectMany(x => x.DeletedAssets).FirstOrDefault(x => x.Id == sourceFileChange.AssetId);

                        if (asset == null)
                        {
                            continue;
                        }

                        // We care only about changes that needs to update
                        if (sourceFileChange.NeedUpdate)
                        {
                            switch (sourceFileChange.Type)
                            {
                            case SourceFileChangeType.Asset:
                                // The asset itself has changed and now references a new source
                                asset.Sources.UpdateUsedHashes(sourceFileChange.Files);
                                break;

                            case SourceFileChangeType.SourceFile:
                                // A source file referenced by the asset has changed
                                asset.Sources.ComputeNeedUpdateFromSource();
                                break;

                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                        // The asset has been updated, remove the change data from the list
                        sourceFileChanges.RemoveAt(i--);

                        if (!asset.IsDeleted)
                        {
                            // We will notify only for undeleted assets
                            changedAssets.Add(asset);
                        }
                    }

                    // Notify all changed assets at once.
                    if (changedAssets.Count > 0)
                    {
                        sessionViewModel.NotifyAssetPropertiesChanged(changedAssets.ToList());
                        changedAssets.Clear();
                    }
                }
            }
        }