Example #1
0
	public static void Pack(HamTimelineNode node, DataPacker packer)
	{
		packer.Pack((byte)node.Type);
		packer.Pack(node.ID);

		packer.Pack(node.PreviousNodeIDs.Count);
		for (int i = 0; i < node.PreviousNodeIDs.Count; ++i)
		{
			packer.Pack(node.PreviousNodeIDs[i]);
		}

		node.Pack(packer);
	}
Example #2
0
		public PlacementNode(HamTimelineNode node, PlacementNode parent)
		{
			this.Node = node;
			this.Parent = parent;
			if (this.Parent != null)
			{
				this.Parent.Children.Add(this);
				this.Depth = this.Parent.Depth + 1;
			}
			else
			{
				this.Depth = 0;
			}
			this.Children = new List<PlacementNode>();
			this.Width = 0;
			this.WidthOffset = 0;
		}
Example #3
0
	public static void Unpack(out HamTimelineNode node, DataUnpacker unpacker)
	{
		byte typeByte;
		unpacker.Unpack(out typeByte);
		TimelineNodeType type = (TimelineNodeType)typeByte;

		int id;
		unpacker.Unpack(out id);

		int numPrevIDs;
		unpacker.Unpack(out numPrevIDs);
		List<int> previousNodeIDs = new List<int>();
		for (int i = 0; i < numPrevIDs; ++i)
		{
			int prevID;
			unpacker.Unpack(out prevID);
			previousNodeIDs.Add(prevID);
		}

		switch (type)
		{
		case TimelineNodeType.Dialog:
			node = new HamDialogNode();
			break;
		case TimelineNodeType.Branch:
			node = new HamBranchNode();
			break;
		case TimelineNodeType.Decision:
			node = new HamDecisionNode();
			break;
		case TimelineNodeType.Consequence:
			node = new HamConsequenceNode();
			break;
		default:
			node = null;
			return;
		}
		node.ID = id;
		node.Type = type;
		node.PreviousNodeIDs = previousNodeIDs;

		node.Unpack(unpacker);
	}
Example #4
0
	// Visualization and Editing
	// Walk up the tree until a dialog node is found
	public HamDialogNode GetLastDialogNode(HamTimelineNode node)
	{
		if (node.Type == TimelineNodeType.Dialog) { return node as HamDialogNode; }
		for (int i = 0; i < node.PreviousNodeIDs.Count; ++i)
		{
			HamDialogNode last = GetLastDialogNode(this.Nodes[node.PreviousNodeIDs[i]]);
			if (last != null)
			{
				return last;
			}
		}
		return null;
	}
Example #5
0
	public bool CanDeleteTree(HamTimelineNode node)
	{
		return node.ID != this.OriginNodeID;
	}
Example #6
0
	public bool CanRemoveCleanly(HamTimelineNode node)
	{
		int dependants = 0;
		List<int> descendants = node.GetDescendantIDs();
		if (descendants.Count == 0 && node.ID == this.OriginNodeID)
		{
			// If we're deleting the origin node, we need a replacement
			return false;
		}
		for (int i = 0; i < descendants.Count; ++i)
		{
			HamTimelineNode d = this.Nodes[descendants[i]];
			if (d.UniquelyParented) { dependants += 1; }
		}
		return dependants < 2;
	}
Example #7
0
	public bool CanLinkCleanly(HamTimelineNode parent, HamTimelineNode child, int i = 0)
	{
		int formerChildID = parent.GetDescendant(i);
		if (formerChildID == InvalidID) { return true; }
		return (child.GetFreeDescendantSlot() != -1);
	}
Example #8
0
	public void LinkNodes(HamTimelineNode parent, HamTimelineNode child, int i = 0)
	{
		// Check for previous linkage
		int formerChildID = parent.GetDescendant(i);
		if (formerChildID != InvalidID)
		{
			HamTimelineNode formerChild = this.Nodes[formerChildID];

			// Remove former linkage
			formerChild.PreviousNodeIDs.Remove(parent.ID);

			// Set former child's parentage to the new child
			int slot = child.GetFreeDescendantSlot();
			child.SetDescendant(formerChild.ID, slot);
			formerChild.PreviousNodeIDs.Add(child.ID);
		}

		// Set new child's parentage and overwrite parent linkage
		parent.SetDescendant(child.ID, i);
		child.PreviousNodeIDs.Add(parent.ID);

		this.NodeLinkageDirty = true;
		SanityCheck();
	}
Example #9
0
	public void DeleteNode(HamTimelineNode node)
	{
		// It's expected that there is at most 1 uniquely parented descendant
		// Find the dependant node, removing linkages to the current node in all descendants as we go
		HamTimelineNode dependant = null;
		List<int> descendants = node.GetDescendantIDs();
		for (int i = 0; i < descendants.Count; ++i)
		{
			HamTimelineNode descendant = this.Nodes[descendants[i]];
			if (descendant.UniquelyParented)
			{
				dependant = descendant;
			}
			descendant.PreviousNodeIDs.Remove(node.ID);
		}

		// Remove linkages to this node in the parents, linking the parents to the dependant node instead if it exists
		for (int i = 0; i < node.PreviousNodeIDs.Count; ++i)
		{
			HamTimelineNode parent = this.Nodes[node.PreviousNodeIDs[i]];
			int pIndex = parent.GetIndexOfDescendant(node.ID);
			parent.SetDescendant((dependant == null) ? InvalidID : dependant.ID, pIndex);
		}

		// If the node we're deleting is the origin, set any descendant (preferably the dependant) as the new origin
		if (node.ID == this.OriginNodeID)
		{
			if (dependant != null)
			{
				this.OriginNodeID = dependant.ID;
			}
			else
			{
				// There is assumed to be at least 1 descendant
				this.OriginNodeID = descendants[0];
			}
		}

		// Remove this node completely
		this.Nodes.Remove(node.ID);

		this.NodeLinkageDirty = true;
		SanityCheck();
	}
Example #10
0
	public void DeleteTree(HamTimelineNode node)
	{
		Queue<HamTimelineNode> toDelete = new Queue<HamTimelineNode>();
		toDelete.Enqueue(node);
		this.Nodes.Remove(node.ID);

		while (toDelete.Count > 0)
		{
			HamTimelineNode del = toDelete.Dequeue();

			// Remove any linkage between this node and its parents
			for (int i = 0; i < del.PreviousNodeIDs.Count; ++i)
			{
				if (!this.Nodes.ContainsKey(del.PreviousNodeIDs[i]))
				{
					// This parent already deleted, ignore it and move on
					continue;
				}
				HamTimelineNode parent = this.Nodes[del.PreviousNodeIDs[i]];
				int pIndex = parent.GetIndexOfDescendant(del.ID);
				parent.SetDescendant(InvalidID, pIndex);
			}

			// Queue up children
			List<int> descendants = del.GetDescendantIDs();
			for (int i = 0; i < descendants.Count; ++i)
			{
				if (!this.Nodes.ContainsKey(descendants[i]))
				{
					// This descendant already deleted, ignore it and move on
					continue;
				}
				HamTimelineNode descendant = this.Nodes[descendants[i]];
				int validParents = 0;
				for (int j = 0; j < descendant.PreviousNodeIDs.Count; ++j)
				{
					if (this.Nodes.ContainsKey(descendant.PreviousNodeIDs[j]) && descendant.PreviousNodeIDs[j] != del.ID)
					{
						validParents += 1;
					}
				}
				descendant.PreviousNodeIDs.Remove(del.ID);
				if (validParents == 0)
				{
					// This node is the only parent of the descendant, it gets deleted as part of the tree
					toDelete.Enqueue(descendant);
					this.Nodes.Remove(descendant.ID);
				}
			}
		}

		this.NodeLinkageDirty = true;
		SanityCheck();
	}
Example #11
0
 public SelectionContext()
 {
     this.Node = null;
     this.Mode = SelectionMode.SelectNode;
     this.DescendantIndex = 0;
 }
Example #12
0
 private void RightClickNodeContext(HamTimelineNode node, int descendantIndex)
 {
     GenericMenu menu = new GenericMenu();
     if (descendantIndex != -1)
     {
         menu.AddItem(
             new GUIContent("Link To Selection"),
             false,
             (a) => { this.selection.BeginLinking(node, descendantIndex); },
             null
         );
         menu.AddItem(
             new GUIContent("Link To New Dialog"),
             false,
             (a) =>
             {
                 HamDialogNode lastDialog = this.activeTimeline.GetLastDialogNode(node);
                 HamTimelineNode newNode = this.activeTimeline.AddDialogNode(
                     lastDialog != null ? lastDialog.SceneID : this.activeTimeline.DefaultSceneID,
                     lastDialog != null ? lastDialog.SpeakerID : this.activeTimeline.NarratorID,
                     "",
                     lastDialog != null ? lastDialog.CharacterIDs : null
                 );
                 this.activeTimeline.LinkNodes(node, newNode, descendantIndex);
             },
             null
         );
         menu.AddItem(
             new GUIContent("Link To New Decision"),
             false,
             () =>
             {
                 HamTimelineNode newNode = this.activeTimeline.AddDecisionNode();
                 this.activeTimeline.LinkNodes(node, newNode, descendantIndex);
             }
         );
         menu.AddItem(
             new GUIContent("Link To New Branch"),
             false,
             () =>
             {
                 HamTimelineNode newNode = this.activeTimeline.AddBranchNode();
                 this.activeTimeline.LinkNodes(node, newNode, descendantIndex);
             }
         );
         menu.AddItem(
             new GUIContent("Link To New Consequence"),
             false,
             () =>
             {
                 HamTimelineNode newNode = this.activeTimeline.AddConsequenceNode();
                 this.activeTimeline.LinkNodes(node, newNode, descendantIndex);
             }
         );
     }
     if (this.activeTimeline.CanRemoveCleanly(node))
     {
         menu.AddItem(
             new GUIContent("Remove Node (Relink Dependants)"),
             false,
             () =>
             {
                 this.activeTimeline.DeleteNode(node);
             }
         );
     }
     if (this.activeTimeline.CanDeleteTree(node))
     {
         menu.AddItem(
             new GUIContent("Remove Node (Delete Dependants)"),
             false,
             () =>
             {
                 this.activeTimeline.DeleteTree(node);
             }
         );
     }
     menu.ShowAsContext();
 }
Example #13
0
 private Vector2 GetOverviewPosition(HamTimelineNode node)
 {
     if (this.overviewNodePlacement == null || !this.overviewNodePlacement.ContainsKey(node.ID)) { return Vector2.zero; }
     Vector2 placement = this.overviewNodePlacement[node.ID];
     return new Vector2(
         placement.x * kNodeSpacingX,
         placement.y * kNodeSpacingY
     );
 }
Example #14
0
 public void BeginLinking(HamTimelineNode node, int index = 0)
 {
     this.Node = node;
     this.DescendantIndex = index;
     this.Mode = SelectionMode.LinkNodes;
 }
Example #15
0
 public void ClickedNode(HamTimeline timeline, HamTimelineNode node)
 {
     switch (this.Mode)
     {
     case SelectionMode.SelectNode:
         this.Node = node;
         break;
     case SelectionMode.LinkNodes:
         if (this.Node != node)
         {
             if (timeline.CanLinkCleanly(this.Node, node, this.DescendantIndex))
             {
                 timeline.LinkNodes(this.Node, node, this.DescendantIndex);
             }
             else
             {
                 EditorUtility.DisplayDialog("Node Linking Failed", "No clean way was found to reparent the currently linked node", "OK");
             }
         }
         this.Mode = SelectionMode.SelectNode;
         break;
     }
 }