/// <summary> /// Initializes a new instance of the <see cref="EditorNavigationViewModel"/> class. /// </summary> /// <param name="editor"></param> /// <param name="serviceProvider">The service provider for this view model.</param> /// <param name="controller">The controller object for the related editor game.</param> public EditorNavigationViewModel([NotNull] IViewModelServiceProvider serviceProvider, [NotNull] IEditorGameController controller, [NotNull] EntityHierarchyEditorViewModel editor) : base(serviceProvider) { if (controller == null) { throw new ArgumentNullException(nameof(controller)); } this.editor = editor; this.controller = controller; ToggleAllGroupsCommand = new AnonymousCommand <bool>(ServiceProvider, value => Visuals.ForEach(x => x.IsVisible = value)); gameSettingsAsset = editor.Session.AllAssets.FirstOrDefault(x => x.AssetType == typeof(GameSettingsAsset)); if (gameSettingsAsset != null) { gameSettingsAsset.PropertyGraph.ItemChanged += GameSettingsPropertyGraphOnItemChanged; gameSettingsAsset.PropertyGraph.Changed += GameSettingsPropertyGraphOnChanged; UpdateNavigationMeshLayers(); } editor.Dispatcher.InvokeTask(async() => { await controller.GameContentLoaded; service = controller.GetService <EditorGameNavigationMeshService>(); UpdateNavigationMeshLayers(); }); }
public EntityFolderViewModel([NotNull] EntityHierarchyEditorViewModel editor, [NotNull] EntityHierarchyViewModel asset, string name, [NotNull] IEnumerable <EntityDesign> entities) : base(editor, asset, entities) { this.name = name; Id = new AbsoluteId(Asset.Id, Guid.NewGuid()); RenameCommand = new AnonymousCommand(ServiceProvider, () => IsEditing = true); }
public EntityViewModel([NotNull] EntityHierarchyEditorViewModel editor, [NotNull] EntityHierarchyViewModel asset, [NotNull] EntityDesign entityDesign) : base(editor, asset, GetOrCreateChildPartDesigns((EntityHierarchyAssetBase)asset.Asset, entityDesign), entityDesign.Entity) { if (entityDesign.Entity == null) { throw new ArgumentException(@"entity must contain a non-null asset entity.", nameof(entityDesign)); } EntityDesign = entityDesign; var assetNode = Editor.NodeContainer.GetOrCreateNode(entityDesign.Entity); nameNodeBinding = new MemberGraphNodeBinding <string>(assetNode[nameof(Entity.Name)], nameof(Name), OnPropertyChanging, OnPropertyChanged, Editor.UndoRedoService); componentsNodeBinding = new ObjectGraphNodeBinding <EntityComponentCollection>(assetNode[nameof(Entity.Components)].Target, nameof(Components), OnPropertyChanging, OnPropertyChanged, Editor.UndoRedoService, false); modelComponent = new ModelComponentViewModel(ServiceProvider, this); particleComponent = new ParticleSystemComponentViewModel(ServiceProvider, this); cameraComponent = new CameraComponentViewModel(ServiceProvider, this); transformationNode = Editor.NodeContainer.GetNode(AssetSideEntity.Transform)[nameof(TransformComponent.Children)].Target; transformationNode.ItemChanging += TransformChildrenChanging; transformationNode.ItemChanged += TransformChildrenChanged; RenameCommand = new AnonymousCommand(ServiceProvider, () => IsEditing = true); FocusOnEntityCommand = new AnonymousCommand(ServiceProvider, FocusOnEntity); UpdateSourcePrefab(); var basePrefabNode = Editor.NodeContainer.GetNode(EntityDesign)[nameof(EntityDesign.Base)]; basePrefabNode.ValueChanged += BasePrefabChanged; }
protected EntityHierarchyRootViewModel([NotNull] EntityHierarchyEditorViewModel editor, [NotNull] EntityHierarchyViewModel asset, [NotNull] string name) : base(editor, asset, asset.Asset.Hierarchy.EnumerateRootPartDesigns(), null) { this.name = name ?? throw new ArgumentNullException(nameof(name)); rootEntitiesNode = Editor.Session.AssetNodeContainer.GetNode(EntityHierarchy.Hierarchy)[nameof(AssetCompositeHierarchyData <EntityDesign, Entity> .RootParts)].Target; rootEntitiesNode.ItemChanging += RootEntitiesChanging; rootEntitiesNode.ItemChanged += RootEntitiesChanged; entitiesNode = Editor.Session.AssetNodeContainer.GetNode(EntityHierarchy.Hierarchy)[nameof(AssetCompositeHierarchyData <EntityDesign, Entity> .Parts)].Target; entitiesNode.ItemChanged += EntitiesChanged; }
protected EntityHierarchyElementViewModel([NotNull] EntityHierarchyEditorViewModel editor, [NotNull] EntityHierarchyViewModel asset, [NotNull] IEnumerable <EntityDesign> childEntities, object assetSideInstance) : base(editor, asset, childEntities) { this.assetSideInstance = assetSideInstance; LoadCommand = new AnonymousTaskCommand <bool>(ServiceProvider, recursive => RequestLoading(!IsLoaded, recursive)); LockCommand = new AnonymousTaskCommand <bool>(ServiceProvider, recursive => RequestLocking(!IsLocked, recursive)); DependentProperties.Add(nameof(IsLoaded), new[] { nameof(IsSelectable) }); DependentProperties.Add(nameof(IsLocked), new[] { nameof(IsSelectable) }); }
protected EntityHierarchyItemViewModel([NotNull] EntityHierarchyEditorViewModel editor, [NotNull] EntityHierarchyViewModel asset, [NotNull] IEnumerable <EntityDesign> childEntities) : base(editor, asset) { if (childEntities == null) { throw new ArgumentNullException(nameof(childEntities)); } // note: we want to ignore case and diacritics (e.g. accentuation) when sorting the folders Folders = new AutoUpdatingSortedObservableCollection <EntityFolderViewModel>((x, y) => string.Compare(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase)); // Note: we make sure that empty folders and null folders are grouped together // TODO: implement a more robust folder grouping method that trims, etc. // TODO: also ensure that empty folder are serialized as null (or vice-versa) to avoid this kind of issue foreach (var folderGroup in childEntities.GroupBy(x => !string.IsNullOrWhiteSpace(x.Folder) ? x.Folder : null).OrderBy(x => x.Key)) { if (!EntityFolderViewModel.GenerateFolder(this, folderGroup.Key, folderGroup)) { foreach (var child in folderGroup) { var viewModel = (EntityViewModel)Editor.CreatePartViewModel(Asset, child); subEntities.Add(viewModel); } } } AddItems(Folders); AddItems(subEntities); // We register the collection changed handler after having added already-existing children Folders.CollectionChanged += FolderCollectionChanged; subEntities.CollectionChanged += SubEntityCollectionChanged; // Add policies for adding/inserting assets // TODO: make it work with plugins (discovery, registration, override...) addAssetPolicies = new List <IAddAssetPolicy> { new AddModelAssetPolicy <ModelAsset>(), new AddModelAssetPolicy <PrefabModelAsset>(), new AddModelAssetPolicy <ProceduralModelAsset>(), new AddPrefabAssetPolicy(), new AddSceneAssetPolicy(), new AddScriptSourceFileAssetPolicy(), new AddSpriteSheetAssetPolicy(), new AddSpriteStudioModelAssetPolicy(), new AddTextureAssetPolicy(), new AddVideoAssetPolicy(), new AddUIPageAssetPolicy(), }; }
/// <summary> /// Initializes a new instance of the <see cref="EditorNavigationViewModel"/> class. /// </summary> /// <param name="serviceProvider">The service provider for this view model.</param> /// <param name="controller">The controller object for the related editor game.</param> public EditorLightingViewModel([NotNull] IViewModelServiceProvider serviceProvider, [NotNull] IEditorGameController controller, [NotNull] EntityHierarchyEditorViewModel editor) : base(serviceProvider) { if (controller == null) { throw new ArgumentNullException(nameof(controller)); } if (editor == null) { throw new ArgumentNullException(nameof(editor)); } this.controller = controller; this.editor = editor; RequestLightProbesComputeCommand = new AnonymousTaskCommand(ServiceProvider, () => RebuildLightProbes(LightProbeBounces)); RequestLightProbesResetCommand = new AnonymousTaskCommand(ServiceProvider, () => RebuildLightProbes(0)); CaptureCubemapCommand = new AnonymousTaskCommand(ServiceProvider, CaptureCubemap); }
public EntityHierarchyElementChangePropagator([NotNull] EntityHierarchyEditorViewModel editor, [NotNull] EntityViewModel owner, [NotNull] Entity assetSidePart) : base(editor, owner, assetSidePart) { }
private async void TransformChildrenChanged(object sender, ItemChangeEventArgs e) { Entity childEntity; switch (e.ChangeType) { case ContentChangeType.CollectionAdd: childEntity = ((TransformComponent)e.NewValue).Entity; Editor.Logger.Verbose($"Add {childEntity.Name} ({childEntity.Id}) to the Entities collection"); break; case ContentChangeType.CollectionRemove: childEntity = ((TransformComponent)e.OldValue).Entity; Editor.Logger.Verbose($"Remove {childEntity.Name} ({childEntity.Id}) from the Entities collection"); break; default: throw new ArgumentOutOfRangeException(); } // Update view model if (e.ChangeType == ContentChangeType.CollectionAdd) { // TODO: can be factorized with what EntityHierarchyRootViewModel is doing, through a base method. There are a few differences though. var component = (TransformComponent)e.NewValue; var entity = EntityHierarchy.Hierarchy.Parts[component.Entity.Id]; var element = (EntityViewModel)Editor.CreatePartViewModel(Asset, entity); var index = e.Index.Int; var parent = FindOrCreateFolder(entity.Folder); parent.InsertEntityViewModel(element, parent.FindIndexInParent(index, EntityDesign.Entity.Transform.Children.Select(x => EntityHierarchy.Hierarchy.Parts[x.Entity.Id]))); // FIXME: when we allow loading/unloading single entities, this should be implemented in OnLoadingRequested. Then just call RequestLoading(true). // Check if the container root is loaded if (EntityHierarchyEditorViewModel.GetRoot(this).IsLoaded) { var children = element.TransformChildren.BreadthFirst(x => x.TransformChildren).ToList(); // Set the new entity and its children as 'loading' element.IsLoading = true; foreach (var child in children) { child.IsLoading = true; } // Add the entity to the game (actually load the entity and its children) await Editor.Controller.AddPart(this, element.AssetSideEntity); // Set the new entity and its children as 'loaded' element.IsLoaded = true; foreach (var child in children) { child.IsLoaded = true; } // Manually notify the game-side scene element.NotifyGameSidePartAdded().Forget(); foreach (var child in children) { child.NotifyGameSidePartAdded().Forget(); } } } else if (e.ChangeType == ContentChangeType.CollectionRemove) { var component = (TransformComponent)e.OldValue; var partId = new AbsoluteId(Asset.Id, component.Entity.Id); var element = (EntityViewModel)Editor.FindPartViewModel(partId); if (element == null) { throw new InvalidOperationException($"{nameof(element)} cannot be null"); } RemoveEntityViewModel(element); // FIXME: when we allow loading/unloading single entities, this should be implemented in OnLoadingRequested. Then just call RequestLoading(false). if (element.IsLoaded) { element.IsLoading = true; Editor.Controller.RemovePart(this, element.AssetSideEntity).Forget(); element.IsLoaded = false; } } }