699 lines
24 KiB
C#
699 lines
24 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using JD.SceneExplorer.Utils;
|
|
using JD.WPF.Models;
|
|
|
|
namespace JD.SceneExplorer.ViewModels
|
|
{
|
|
public class SceneTree : ObjectWithRef
|
|
{
|
|
public const string SceneFileExtension = "isc";
|
|
|
|
private readonly ObservableCollection<SceneTree> m_childScenesInternal = new ObservableCollection<SceneTree>();
|
|
private readonly ObservableCollection<Actor> m_actorsInternal = new ObservableCollection<Actor>();
|
|
private readonly ObservableCollection<Frise> m_frisesInternal = new ObservableCollection<Frise>();
|
|
|
|
private readonly ReadOnlyObservableCollection<SceneTree> m_childScenes;
|
|
private readonly ReadOnlyObservableCollection<Actor> m_actors;
|
|
private readonly ReadOnlyObservableCollection<Frise> m_frises;
|
|
|
|
private String m_uniqueName;
|
|
private String m_path;
|
|
private uint m_relatedActorRef;
|
|
|
|
public SceneTree(uint objectRef, SceneTree parent, System.ComponentModel.PropertyChangedEventHandler propertyChangedHandler)
|
|
: base(objectRef, parent, propertyChangedHandler)
|
|
{
|
|
m_childScenes = new ReadOnlyObservableCollection<SceneTree>(m_childScenesInternal);
|
|
m_actors = new ReadOnlyObservableCollection<Actor>(m_actorsInternal);
|
|
m_frises = new ReadOnlyObservableCollection<Frise>(m_frisesInternal);
|
|
m_relatedActorRef = ObjectWithRef.InvalidObject.ObjectRef;
|
|
}
|
|
|
|
public SceneTree(uint objectRef, SceneTree parent)
|
|
: this(objectRef, parent, parent != null ? parent.PropertyChangedHandler : null)
|
|
{
|
|
|
|
}
|
|
|
|
public override ObjectWithRefType Type { get { return ObjectWithRefType.Scene; } }
|
|
|
|
protected override void LoadChildren()
|
|
{
|
|
List<ObjectWithRef> itemsToAdd = new List<ObjectWithRef>();
|
|
itemsToAdd.Capacity = m_childScenes.Count + m_actors.Count + m_frises.Count;
|
|
foreach (ObjectWithRef itemToAdd in m_childScenes.Union<ObjectWithRef>(m_actors).Union<ObjectWithRef>(m_frises))
|
|
{
|
|
//if (itemToAdd.IsFiltered)
|
|
// continue;
|
|
|
|
if (Children.FirstOrDefault(child => child == itemToAdd) != null)
|
|
continue;
|
|
|
|
// TODO : Triggers a lot of events. Override ObservableCollection to add an AddRange function?
|
|
if (Children.Count == 0)
|
|
Children.Add(itemToAdd);
|
|
else
|
|
Children.Insert(FindInsertPosition(itemToAdd), itemToAdd);
|
|
|
|
itemToAdd.UpdateChildren();
|
|
}
|
|
|
|
// Use optimized filling if available.
|
|
//if (Children is MultiThreadedObservableRangeCollection<ITreeViewItemData>)
|
|
//{
|
|
// (Children as MultiThreadedObservableRangeCollection<ITreeViewItemData>).AddRange(itemsToAdd);
|
|
//}
|
|
//else
|
|
//{
|
|
// foreach (ObjectWithRef itemToAdd in itemsToAdd)
|
|
// Children.Add(itemToAdd);
|
|
//}
|
|
|
|
UpdateFlags(false);
|
|
}
|
|
|
|
protected override int GetChildrenCount()
|
|
{
|
|
return m_childScenes.Count + m_actors.Count + m_frises.Count;
|
|
}
|
|
|
|
public override uint PickableRef
|
|
{
|
|
get { return ObjectWithRef.InvalidObject.ObjectRef; }
|
|
}
|
|
|
|
public override bool CanHide { get { return false; } }
|
|
|
|
public override bool Visible
|
|
{
|
|
get
|
|
{
|
|
if (!ChildrenLoaded)
|
|
return false;
|
|
if (Children.Count == 0)
|
|
return true;
|
|
else
|
|
return Children.Cast<ObjectWithRef>().Any(child => child.Visible);
|
|
}
|
|
set
|
|
{
|
|
if (Visible != value)
|
|
{
|
|
if (ChildrenLoaded)
|
|
{
|
|
foreach (ObjectWithRef child in Children)
|
|
child.Visible = value;
|
|
}
|
|
|
|
SceneTree parent = Parent as SceneTree;
|
|
while (parent != null)
|
|
{
|
|
(Parent as SceneTree).RaisePropertyChanged("Visible");
|
|
parent = parent.Parent as SceneTree;
|
|
}
|
|
|
|
m_visible = value;
|
|
RaisePropertyChanged("Visible");
|
|
}
|
|
}
|
|
}
|
|
|
|
public string UniqueName
|
|
{
|
|
get { return m_uniqueName; }
|
|
set
|
|
{
|
|
if (m_uniqueName != value)
|
|
{
|
|
m_uniqueName = value;
|
|
RaisePropertyChanged("UniqueName");
|
|
}
|
|
}
|
|
}
|
|
|
|
public string Path
|
|
{
|
|
get { return m_path; }
|
|
set
|
|
{
|
|
if (m_path != value)
|
|
{
|
|
m_path = value;
|
|
FilePath = m_path;
|
|
RaisePropertyChanged("Path");
|
|
}
|
|
}
|
|
}
|
|
|
|
public uint RelatedActorRef
|
|
{
|
|
get { return m_relatedActorRef; }
|
|
set
|
|
{
|
|
if (m_relatedActorRef != value)
|
|
{
|
|
m_relatedActorRef = value;
|
|
RaisePropertyChanged("RelatedActorRef");
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual bool IsLockAvailable { get { return false; } }
|
|
|
|
/// <summary>
|
|
/// Applies filter to elements of the current scene.
|
|
/// </summary>
|
|
/// <param name="filterData">The filter string. </param>
|
|
/// <returns>True if the scene is filtered, false otherwise. </returns>
|
|
public override bool SetFilter(object filterData)
|
|
{
|
|
return SetFilter(filterData, System.Threading.CancellationToken.None);
|
|
}
|
|
|
|
public override bool SetFilter(object filterData, System.Threading.CancellationToken cancellationToken)
|
|
{
|
|
bool isSceneFiltered = base.SetFilter(filterData, cancellationToken);
|
|
TagSelectorData newFilter = (TagSelectorData)filterData;
|
|
if (isSceneFiltered || (newFilter != null && !newFilter.IsFiltering))
|
|
{
|
|
foreach (Actor actor in m_actors)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
IsFiltered &= actor.SetFilter(newFilter, cancellationToken);
|
|
}
|
|
foreach (Frise frise in m_frises)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
IsFiltered &= frise.SetFilter(newFilter, cancellationToken);
|
|
}
|
|
foreach (SceneTree subScene in m_childScenes)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
IsFiltered &= subScene.SetFilter(newFilter, cancellationToken);
|
|
}
|
|
if (newFilter.IsFiltering && !IsFiltered)
|
|
IsExpanded = true;
|
|
}
|
|
else
|
|
{
|
|
SetFilterAndForceVisibility(newFilter);
|
|
IsFiltered = false;
|
|
}
|
|
|
|
return IsFiltered;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies filter to elements of the current scene. All child elements are visible. This function acts only on expanded state.
|
|
/// </summary>
|
|
/// <param name="newFilter">The filter string. </param>
|
|
/// <returns>True if the scene is filtered, false otherwise. </returns>
|
|
private bool SetFilterAndForceVisibility(TagSelectorData newFilter)
|
|
{
|
|
return SetFilterAndForceVisibility(newFilter, System.Threading.CancellationToken.None);
|
|
}
|
|
|
|
private bool SetFilterAndForceVisibility(TagSelectorData newFilter, System.Threading.CancellationToken cancellationToken)
|
|
{
|
|
// Force parent expand, but do not expand the current node. It will stay collapsed unless a child matches the filter.
|
|
IsExpanded = true;
|
|
|
|
bool childMatchFilter = false;
|
|
foreach (Actor actor in m_actors)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
childMatchFilter |= !actor.SetFilter(newFilter, cancellationToken);
|
|
actor.IsFiltered = false;
|
|
}
|
|
foreach (Frise frise in m_frises)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
childMatchFilter |= !frise.SetFilter(newFilter, cancellationToken);
|
|
frise.IsFiltered = false;
|
|
}
|
|
foreach (SceneTree subScene in m_childScenes)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
bool sceneFiltered = subScene.SetFilterAndForceVisibility(newFilter, cancellationToken);
|
|
childMatchFilter |= !sceneFiltered;
|
|
subScene.IsFiltered = sceneFiltered;
|
|
subScene.IsFiltered = false;
|
|
}
|
|
|
|
if (!childMatchFilter)
|
|
{
|
|
IsExpanded = false;
|
|
}
|
|
|
|
return !childMatchFilter;
|
|
}
|
|
|
|
public ReadOnlyObservableCollection<SceneTree> ChildScenes { get { return m_childScenes; } }
|
|
public ReadOnlyObservableCollection<Actor> Actors { get { return m_actors; } }
|
|
public ReadOnlyObservableCollection<Frise> Frises { get { return m_frises; } }
|
|
|
|
public static SceneTree LoadFromBlob(JD.Remoting.IBlob _blob, SceneTree parent)
|
|
{
|
|
string uniqueName = _blob.ExtractString();
|
|
string path = _blob.ExtractPath();
|
|
string friendlyName = _blob.ExtractString();
|
|
uint objectRef = _blob.ExtractUInt();
|
|
uint relatedActorRef = _blob.ExtractUInt();
|
|
bool isWorldActive = _blob.ExtractBool();
|
|
uint tagsCount = _blob.ExtractUInt();
|
|
List<string> tags = new List<string>();
|
|
for (int i = 0; i < tagsCount; i++)
|
|
tags.Add(_blob.ExtractString());
|
|
|
|
SceneTree newSceneTree = new SceneTree(objectRef, parent);
|
|
newSceneTree.LoadFromBlobInternal(_blob, uniqueName, path, friendlyName, relatedActorRef, isWorldActive, tags);
|
|
return newSceneTree;
|
|
}
|
|
|
|
protected void LoadFromBlobInternal(JD.Remoting.IBlob _blob, string uniqueName, string path, string friendlyName, uint relatedActorRef, bool isWorldActive, List<string> tags)
|
|
{
|
|
UniqueName = uniqueName;
|
|
Path = path;
|
|
FriendlyName = friendlyName;
|
|
RelatedActorRef = relatedActorRef;
|
|
Active = isWorldActive;
|
|
|
|
foreach (string tag in tags)
|
|
Tags.Add(tag);
|
|
AddSpecialTags();
|
|
|
|
//extract actors
|
|
uint actorCount = _blob.ExtractUInt();
|
|
for (uint actorIndex = 0; actorIndex < actorCount; actorIndex++)
|
|
{
|
|
var newActor = Actor.LoadFromBlob(_blob, this);
|
|
InsertActor(newActor);
|
|
}
|
|
|
|
//extract frises
|
|
uint friseCount = _blob.ExtractUInt();
|
|
for (uint friseIndex = 0; friseIndex < friseCount; friseIndex++)
|
|
{
|
|
var newFrise = Frise.LoadFromBlob(_blob, this);
|
|
InsertFrise(newFrise);
|
|
}
|
|
|
|
ExtractSubScenes(_blob);
|
|
IconSource = EditorIconsManager.Instance.GetIconLocationFromTags(Tags);
|
|
NeedUpdate = true;
|
|
}
|
|
|
|
protected void AddSpecialTags()
|
|
{
|
|
if (Path.EndsWith(".isc") && (Tags.FirstOrDefault(tag => tag == "isc") == null))
|
|
Tags.Add("isc");
|
|
if (FriendlyName.EndsWith("_LD"))
|
|
Tags.Add("isc_ld_square");
|
|
else if (FriendlyName.EndsWith("_GRAPH"))
|
|
Tags.Add("isc_graph_square");
|
|
else if (FriendlyName.EndsWith("_CINE"))
|
|
Tags.Add("isc_cine_square");
|
|
else if (FriendlyName.EndsWith("_SOUND"))
|
|
Tags.Add("isc_sound_square");
|
|
else if (FriendlyName.EndsWith("_FX"))
|
|
Tags.Add("isc_fx_square");
|
|
}
|
|
|
|
protected virtual void ExtractSubScenes(JD.Remoting.IBlob _blob)
|
|
{
|
|
//extract subscenes
|
|
uint childCount = _blob.ExtractUInt();
|
|
for (uint childIndex = 0; childIndex < childCount; childIndex++)
|
|
{
|
|
var newChildSceneTree = SubSceneTree.LoadFromBlob(_blob, this);
|
|
InsertSubScene(newChildSceneTree);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// find a scene by sceneRef among all hierarchy
|
|
/// </summary>
|
|
/// <param name="_sceneRef"></param>
|
|
/// <returns></returns>
|
|
public SceneTree FindScene(uint _sceneRef)
|
|
{
|
|
if (_sceneRef == m_objectRef)
|
|
return this;
|
|
foreach (SceneTree subscene in m_childScenes)
|
|
{
|
|
SceneTree foundScene = subscene.FindScene(_sceneRef);
|
|
if (foundScene != null)
|
|
{
|
|
return foundScene;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public SceneTree FindScene(string friendlyName, bool recursive = true)
|
|
{
|
|
foreach (SceneTree subScene in m_childScenes)
|
|
{
|
|
if (subScene.FriendlyName == friendlyName)
|
|
return subScene;
|
|
if (recursive)
|
|
{
|
|
SceneTree foundScene = subScene.FindScene(friendlyName);
|
|
if (foundScene != null)
|
|
return foundScene;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public SceneTree FindSceneActor(uint _sceneActorRef)
|
|
{
|
|
if (_sceneActorRef == m_relatedActorRef)
|
|
return this;
|
|
foreach (SceneTree subscene in m_childScenes)
|
|
{
|
|
SceneTree foundScene = subscene.FindSceneActor(_sceneActorRef);
|
|
if (foundScene != null)
|
|
{
|
|
return foundScene;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public ObjectWithRef FindObject(uint _objRef)
|
|
{
|
|
// FIXME : Ugly.
|
|
return FindObject(new ObjectWithRef(_objRef, null, null));
|
|
}
|
|
|
|
public ObjectWithRef FindObject(ObjectWithRef _objRef)
|
|
{
|
|
if (Equals(_objRef))
|
|
return _objRef;
|
|
|
|
ObjectWithRef objRef;
|
|
objRef = Actors.FirstOrDefault(actor => actor.Equals(_objRef));
|
|
if (objRef != null)
|
|
return objRef;
|
|
|
|
objRef = Frises.FirstOrDefault(frise => frise.Equals(_objRef));
|
|
if (objRef != null)
|
|
return objRef;
|
|
|
|
foreach (SceneTree subScene in ChildScenes)
|
|
{
|
|
if (subScene.RelatedActorRef == _objRef.ObjectRef)
|
|
return subScene;
|
|
|
|
objRef = subScene.FindObject(_objRef);
|
|
if (objRef != null)
|
|
return objRef;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public ObjectWithRef FindObject(string friendlyName, bool recursive = true)
|
|
{
|
|
foreach (Actor actor in m_actors)
|
|
{
|
|
if (actor.FriendlyName == friendlyName)
|
|
return actor;
|
|
}
|
|
|
|
foreach (Frise frise in m_frises)
|
|
{
|
|
if (frise.FriendlyName == friendlyName)
|
|
return frise;
|
|
}
|
|
|
|
SceneTree subScene = FindScene(friendlyName, recursive);
|
|
if (subScene != null)
|
|
return subScene;
|
|
|
|
return null;
|
|
}
|
|
|
|
//private int FindInsertPosition(List<ObjectWithRef> targetList, ObjectWithRef objectRef)
|
|
//{
|
|
// return FindInsertPosition(targetList, objectRef, 0, targetList.Count);
|
|
//}
|
|
|
|
//private int FindInsertPosition(List<ObjectWithRef> targetList, ObjectWithRef objectRef, int begin, int end)
|
|
//{
|
|
// if (begin == end)
|
|
// return begin;
|
|
|
|
// int current = (begin + end) / 2;
|
|
// ObjectWithRef curObjectRef = targetList[current] as ObjectWithRef;
|
|
// int compareResult = curObjectRef.CompareTo(objectRef);
|
|
// if (compareResult == 0)
|
|
// return current;
|
|
// else if (compareResult < 0)
|
|
// return FindInsertPosition(targetList, objectRef, current + 1, end);
|
|
// else
|
|
// return FindInsertPosition(targetList, objectRef, begin, current);
|
|
//}
|
|
|
|
private int FindInsertPosition(ObjectWithRef objectRef)
|
|
{
|
|
return FindInsertPosition(objectRef, 0, Children.Count);
|
|
}
|
|
|
|
private int FindInsertPosition(ObjectWithRef objectRef, int begin, int end)
|
|
{
|
|
if (begin == end)
|
|
return begin;
|
|
|
|
int current = (begin + end) / 2;
|
|
ObjectWithRef curObjectRef = Children[current] as ObjectWithRef;
|
|
int compareResult = curObjectRef.CompareTo(objectRef);
|
|
if (compareResult == 0)
|
|
return current;
|
|
else if (compareResult < 0)
|
|
return FindInsertPosition(objectRef, current + 1, end);
|
|
else
|
|
return FindInsertPosition(objectRef, begin, current);
|
|
}
|
|
|
|
|
|
public void InsertActor(Actor newActor)
|
|
{
|
|
m_actorsInternal.Add(newActor);
|
|
NeedUpdate = true;
|
|
}
|
|
|
|
public void InsertFrise(Frise newFrise)
|
|
{
|
|
m_frisesInternal.Add(newFrise);
|
|
NeedUpdate = true;
|
|
}
|
|
|
|
public void InsertSubScene(SceneTree newSubScene)
|
|
{
|
|
m_childScenesInternal.Add(newSubScene);
|
|
Actor actor = m_actorsInternal.FirstOrDefault(act => act.ObjectRef == newSubScene.m_relatedActorRef);
|
|
if (actor != null)
|
|
m_actorsInternal.Remove(actor);
|
|
|
|
NeedUpdate = true;
|
|
}
|
|
|
|
public void RemoveActor(Actor actor)
|
|
{
|
|
Actor objectRef = m_actorsInternal.FirstOrDefault(curActor => curActor == actor);
|
|
if (objectRef != null)
|
|
{
|
|
m_actorsInternal.Remove(objectRef);
|
|
NeedUpdate = true;
|
|
}
|
|
}
|
|
|
|
public void RemoveFrise(Frise frise)
|
|
{
|
|
Frise objectRef = m_frisesInternal.FirstOrDefault(curFrise => curFrise == frise);
|
|
if (objectRef != null)
|
|
{
|
|
m_frisesInternal.Remove(objectRef);
|
|
NeedUpdate = true;
|
|
}
|
|
}
|
|
|
|
public void ClearScene()
|
|
{
|
|
m_actorsInternal.Clear();
|
|
m_frisesInternal.Clear();
|
|
m_childScenesInternal.Clear();
|
|
UnregisterPropertyChanged();
|
|
NeedUpdate = true;
|
|
}
|
|
|
|
public void ClearSelection()
|
|
{
|
|
IsSelected = false;
|
|
foreach (Actor actor in Actors)
|
|
actor.IsSelected = false;
|
|
foreach (Frise frise in Frises)
|
|
frise.IsSelected = false;
|
|
foreach (SceneTree subSceneTree in ChildScenes)
|
|
{
|
|
subSceneTree.IsSelected = false;
|
|
subSceneTree.ClearSelection();
|
|
}
|
|
}
|
|
|
|
public void GetSelection(List<ObjectWithRef> selectedItems, bool includeScenes)
|
|
{
|
|
selectedItems.AddRange(Actors.Union<ObjectWithRef>(Frises).Where(objRef => objRef.IsSelected));
|
|
if (includeScenes)
|
|
selectedItems.AddRange(ChildScenes.Where(objRef => objRef.IsSelected));
|
|
foreach (SceneTree subScene in ChildScenes)
|
|
subScene.GetSelection(selectedItems, includeScenes);
|
|
}
|
|
}
|
|
|
|
public class RootSceneTree : SceneTree, IEquatable<RootSceneTree>
|
|
{
|
|
public RootSceneTree(System.ComponentModel.PropertyChangedEventHandler propertyChangedHandler)
|
|
: base(0, null, propertyChangedHandler)
|
|
{
|
|
ShouldShowRoot = false;
|
|
}
|
|
|
|
public override ObjectWithRefType Type { get { return ObjectWithRefType.RootScene; } }
|
|
|
|
public void LoadFromBlob(JD.Remoting.IBlob _blob)
|
|
{
|
|
string uniqueName = _blob.ExtractString();
|
|
string path = _blob.ExtractPath();
|
|
string friendlyName = _blob.ExtractString();
|
|
uint objectRef = _blob.ExtractUInt();
|
|
uint relatedActorRef = _blob.ExtractUInt();
|
|
bool isWorldActive = _blob.ExtractBool();
|
|
uint tagsCount = _blob.ExtractUInt();
|
|
List<string> tags = new List<string>();
|
|
for (int i = 0; i < tagsCount; i++)
|
|
tags.Add(_blob.ExtractString());
|
|
|
|
if (ObjectRef != objectRef)
|
|
throw new InvalidOperationException("Object references not matching. ");
|
|
|
|
LoadFromBlobInternal(_blob, uniqueName, path, friendlyName, relatedActorRef, isWorldActive, tags);
|
|
NeedUpdate = true;
|
|
}
|
|
|
|
protected override void ExtractSubScenes(JD.Remoting.IBlob _blob)
|
|
{
|
|
//extract subscenes
|
|
uint childCount = _blob.ExtractUInt();
|
|
for (uint childIndex = 0; childIndex < childCount; childIndex++)
|
|
{
|
|
var newChildSceneTree = SceneTree.LoadFromBlob(_blob, this);
|
|
InsertSubScene(newChildSceneTree);
|
|
}
|
|
}
|
|
|
|
public override uint PickableRef
|
|
{
|
|
get { return ObjectWithRef.InvalidObject.ObjectRef; }
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool Equals(RootSceneTree other)
|
|
{
|
|
return this.Id == (other?.Id).GetValueOrDefault(Guid.Empty);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (ReferenceEquals(null, obj)) return false;
|
|
if (ReferenceEquals(this, obj)) return true;
|
|
if (obj.GetType() != this.GetType()) return false;
|
|
return Equals((RootSceneTree) obj);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override int GetHashCode()
|
|
{
|
|
return this.Id.GetHashCode();
|
|
}
|
|
|
|
public Guid Id { get; } = Guid.NewGuid();
|
|
}
|
|
|
|
public class SubSceneTree : SceneTree
|
|
{
|
|
public SubSceneTree(uint objectRef, SceneTree parent)
|
|
: base(objectRef, parent)
|
|
{
|
|
|
|
}
|
|
|
|
public override ObjectWithRefType Type { get { return ObjectWithRefType.SubScene; } }
|
|
|
|
// TODO : Find a clean way to remove this duplicate code ...
|
|
public new static SubSceneTree LoadFromBlob(JD.Remoting.IBlob _blob, SceneTree parent)
|
|
{
|
|
string uniqueName = _blob.ExtractString();
|
|
string path = _blob.ExtractPath();
|
|
string friendlyName = _blob.ExtractString();
|
|
uint objectRef = _blob.ExtractUInt();
|
|
uint relatedActorRef = _blob.ExtractUInt();
|
|
bool isWorldActive = _blob.ExtractBool();
|
|
uint tagsCount = _blob.ExtractUInt();
|
|
List<string> tags = new List<string>();
|
|
for (int i = 0; i < tagsCount; i++)
|
|
tags.Add(_blob.ExtractString());
|
|
|
|
SubSceneTree newSceneTree = new SubSceneTree(objectRef, parent);
|
|
newSceneTree.LoadFromBlobInternal(_blob, uniqueName, path, friendlyName, relatedActorRef, isWorldActive, tags);
|
|
return newSceneTree;
|
|
}
|
|
|
|
public override bool CanHide { get { return true; } }
|
|
|
|
public override bool Visible
|
|
{
|
|
get
|
|
{
|
|
if (!ChildrenLoaded)
|
|
return false;
|
|
if (Children.Count == 0)
|
|
return m_visible;
|
|
else
|
|
return Children.Cast<ObjectWithRef>().Any(child => child.Visible);
|
|
}
|
|
set
|
|
{
|
|
base.Visible = value;
|
|
}
|
|
}
|
|
|
|
public override uint PickableRef
|
|
{
|
|
get
|
|
{
|
|
if (RelatedActorRef != ObjectWithRef.InvalidObject.ObjectRef)
|
|
return RelatedActorRef;
|
|
else
|
|
return base.PickableRef;
|
|
}
|
|
}
|
|
|
|
public override bool IsLockAvailable
|
|
{
|
|
get
|
|
{
|
|
if (Parent is SceneTree && !(Parent is SubSceneTree))
|
|
return true;
|
|
return base.IsLockAvailable;
|
|
}
|
|
}
|
|
}
|
|
}
|