From 0182960cb64011a6acfe7529a9e3272d82ac2e16 Mon Sep 17 00:00:00 2001 From: OMCH <44061383+Owmacohe@users.noreply.github.com> Date: Tue, 26 Dec 2023 18:34:57 -0500 Subject: [PATCH] [docs, website] Final comments - Added comments to all uncommented remaining files - Updated README a bit - Added website - Updated package.json --- Components/{Nodes.meta => Custom.meta} | 0 Components/{Nodes => Custom}/ChangedChoice.cs | 6 +- .../{Nodes => Custom}/ChangedChoice.cs.meta | 0 .../{Nodes => Custom}/ChangedResponse.cs | 6 +- .../{Nodes => Custom}/ChangedResponse.cs.meta | 0 Components/{Nodes => Custom}/Event.cs | 6 +- Components/{Nodes => Custom}/Event.cs.meta | 0 Components/{Nodes => Custom}/Interruptable.cs | 6 +- .../{Nodes => Custom}/Interruptable.cs.meta | 0 Components/{Nodes => Custom}/LockedChoice.cs | 6 +- .../{Nodes => Custom}/LockedChoice.cs.meta | 0 Components/{Nodes => Custom}/Log.cs | 6 +- Components/{Nodes => Custom}/Log.cs.meta | 0 .../{Nodes => Custom}/PortraitChange.cs | 8 +- .../{Nodes => Custom}/PortraitChange.cs.meta | 0 .../{Nodes => Custom}/RandomizedChoice.cs | 6 +- .../RandomizedChoice.cs.meta | 0 .../{Nodes => Custom}/RelationshipChange.cs | 6 +- .../RelationshipChange.cs.meta | 0 .../{Nodes => Custom}/StatisticChange.cs | 6 +- .../{Nodes => Custom}/StatisticChange.cs.meta | 0 .../{Nodes => Custom}/StatisticReveal.cs | 6 +- .../{Nodes => Custom}/StatisticReveal.cs.meta | 0 Components/{Nodes => Custom}/TimedChoice.cs | 6 +- .../{Nodes => Custom}/TimedChoice.cs.meta | 0 Components/{Nodes => Custom}/TopicChange.cs | 6 +- .../{Nodes => Custom}/TopicChange.cs.meta | 0 Components/DescantActor.cs | 51 ++- Components/DescantComponent.cs | 164 ++++++++++ ...onent.cs.meta => DescantComponent.cs.meta} | 0 Components/DescantComponentUtilities.cs | 135 ++++++-- Components/DescantNodeComponent.cs | 137 -------- Components/DescantNodeInvokeResult.cs | 98 ++++++ Components/DescantNodeInvokeResult.cs.meta | 3 + Documentation/Website.meta | 3 + Documentation/Website/components.js | 200 ++++++++++++ Documentation/Website/components.js.meta | 3 + Documentation/Website/index.html | 150 +++++++++ Documentation/Website/index.html.meta | 3 + Documentation/Website/style.css | 124 ++++++++ Documentation/Website/style.css.meta | 3 + Documentation/planning.meta | 8 - Documentation/todo.md | 7 +- Editor/Data/DescantGraphData.cs | 90 +++++- Editor/Data/DescantNodesData.cs | 134 +++++++- Editor/Data/DescantOtherData.cs | 126 ++++++-- Editor/DescantEditorUtilities.cs | 4 +- Editor/DescantNodeComponentVisualElement.cs | 14 +- Editor/Nodes/DescantChoiceNode.cs | 5 + Editor/Nodes/DescantEndNode.cs | 5 + Editor/Nodes/DescantNode.cs | 61 ++-- Editor/Nodes/DescantNodeGroup.cs | 5 + Editor/Nodes/DescantResponseNode.cs | 5 + Editor/Nodes/DescantStartNode.cs | 5 + Editor/Window/DescantActorEditor.cs | 292 ++++++++++++------ Editor/Window/DescantEditor.cs | 92 +++--- Editor/Window/DescantGraphView.cs | 128 ++++---- README.md | 4 +- package-lock.json | 2 +- package.json | 15 +- 60 files changed, 1673 insertions(+), 483 deletions(-) rename Components/{Nodes.meta => Custom.meta} (100%) rename Components/{Nodes => Custom}/ChangedChoice.cs (93%) rename Components/{Nodes => Custom}/ChangedChoice.cs.meta (100%) rename Components/{Nodes => Custom}/ChangedResponse.cs (92%) rename Components/{Nodes => Custom}/ChangedResponse.cs.meta (100%) rename Components/{Nodes => Custom}/Event.cs (88%) rename Components/{Nodes => Custom}/Event.cs.meta (100%) rename Components/{Nodes => Custom}/Interruptable.cs (92%) rename Components/{Nodes => Custom}/Interruptable.cs.meta (100%) rename Components/{Nodes => Custom}/LockedChoice.cs (92%) rename Components/{Nodes => Custom}/LockedChoice.cs.meta (100%) rename Components/{Nodes => Custom}/Log.cs (75%) rename Components/{Nodes => Custom}/Log.cs.meta (100%) rename Components/{Nodes => Custom}/PortraitChange.cs (89%) rename Components/{Nodes => Custom}/PortraitChange.cs.meta (100%) rename Components/{Nodes => Custom}/RandomizedChoice.cs (79%) rename Components/{Nodes => Custom}/RandomizedChoice.cs.meta (100%) rename Components/{Nodes => Custom}/RelationshipChange.cs (91%) rename Components/{Nodes => Custom}/RelationshipChange.cs.meta (100%) rename Components/{Nodes => Custom}/StatisticChange.cs (90%) rename Components/{Nodes => Custom}/StatisticChange.cs.meta (100%) rename Components/{Nodes => Custom}/StatisticReveal.cs (89%) rename Components/{Nodes => Custom}/StatisticReveal.cs.meta (100%) rename Components/{Nodes => Custom}/TimedChoice.cs (93%) rename Components/{Nodes => Custom}/TimedChoice.cs.meta (100%) rename Components/{Nodes => Custom}/TopicChange.cs (88%) rename Components/{Nodes => Custom}/TopicChange.cs.meta (100%) create mode 100644 Components/DescantComponent.cs rename Components/{DescantNodeComponent.cs.meta => DescantComponent.cs.meta} (100%) delete mode 100644 Components/DescantNodeComponent.cs create mode 100644 Components/DescantNodeInvokeResult.cs create mode 100644 Components/DescantNodeInvokeResult.cs.meta create mode 100644 Documentation/Website.meta create mode 100644 Documentation/Website/components.js create mode 100644 Documentation/Website/components.js.meta create mode 100644 Documentation/Website/index.html create mode 100644 Documentation/Website/index.html.meta create mode 100644 Documentation/Website/style.css create mode 100644 Documentation/Website/style.css.meta delete mode 100644 Documentation/planning.meta diff --git a/Components/Nodes.meta b/Components/Custom.meta similarity index 100% rename from Components/Nodes.meta rename to Components/Custom.meta diff --git a/Components/Nodes/ChangedChoice.cs b/Components/Custom/ChangedChoice.cs similarity index 93% rename from Components/Nodes/ChangedChoice.cs rename to Components/Custom/ChangedChoice.cs index c0996a7..68dc0cb 100644 --- a/Components/Nodes/ChangedChoice.cs +++ b/Components/Custom/ChangedChoice.cs @@ -1,11 +1,13 @@ -using System; +// Please see https://omch.tech/descant/#changedchoice for documentation + +using System; using System.Collections.Generic; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(float.PositiveInfinity), NodeType(DescantNodeType.Choice)] - public class ChangedChoice : DescantNodeComponent + public class ChangedChoice : DescantComponent { [Inline] public string ActorName; diff --git a/Components/Nodes/ChangedChoice.cs.meta b/Components/Custom/ChangedChoice.cs.meta similarity index 100% rename from Components/Nodes/ChangedChoice.cs.meta rename to Components/Custom/ChangedChoice.cs.meta diff --git a/Components/Nodes/ChangedResponse.cs b/Components/Custom/ChangedResponse.cs similarity index 92% rename from Components/Nodes/ChangedResponse.cs rename to Components/Custom/ChangedResponse.cs index b685d55..28a1d64 100644 --- a/Components/Nodes/ChangedResponse.cs +++ b/Components/Custom/ChangedResponse.cs @@ -1,11 +1,13 @@ -using System; +// Please see https://omch.tech/descant/#changedresponse for documentation + +using System; using System.Collections.Generic; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(float.PositiveInfinity), NodeType(DescantNodeType.Response)] - public class ChangedResponse : DescantNodeComponent + public class ChangedResponse : DescantComponent { [Inline] public string ActorName; diff --git a/Components/Nodes/ChangedResponse.cs.meta b/Components/Custom/ChangedResponse.cs.meta similarity index 100% rename from Components/Nodes/ChangedResponse.cs.meta rename to Components/Custom/ChangedResponse.cs.meta diff --git a/Components/Nodes/Event.cs b/Components/Custom/Event.cs similarity index 88% rename from Components/Nodes/Event.cs rename to Components/Custom/Event.cs index 8088e21..84c097e 100644 --- a/Components/Nodes/Event.cs +++ b/Components/Custom/Event.cs @@ -1,10 +1,12 @@ -using System; +// Please see https://omch.tech/descant/#event for documentation + +using System; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(float.PositiveInfinity), NodeType(DescantNodeType.Any)] - public class Event : DescantNodeComponent + public class Event : DescantComponent { [Inline] public string ObjectTag; [ParameterGroup("Script to find")] public string ScriptName; diff --git a/Components/Nodes/Event.cs.meta b/Components/Custom/Event.cs.meta similarity index 100% rename from Components/Nodes/Event.cs.meta rename to Components/Custom/Event.cs.meta diff --git a/Components/Nodes/Interruptable.cs b/Components/Custom/Interruptable.cs similarity index 92% rename from Components/Nodes/Interruptable.cs rename to Components/Custom/Interruptable.cs index a103897..5626d37 100644 --- a/Components/Nodes/Interruptable.cs +++ b/Components/Custom/Interruptable.cs @@ -1,10 +1,12 @@ -using System; +// Please see https://omch.tech/descant/#interruptable for documentation + +using System; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(float.PositiveInfinity), NodeType(DescantNodeType.Response)] - public class Interruptable : DescantNodeComponent + public class Interruptable : DescantComponent { [ParameterGroup("Keys/buttons to check")] public string KeyCode; [ParameterGroup("Keys/buttons to check")] public string ButtonName; diff --git a/Components/Nodes/Interruptable.cs.meta b/Components/Custom/Interruptable.cs.meta similarity index 100% rename from Components/Nodes/Interruptable.cs.meta rename to Components/Custom/Interruptable.cs.meta diff --git a/Components/Nodes/LockedChoice.cs b/Components/Custom/LockedChoice.cs similarity index 92% rename from Components/Nodes/LockedChoice.cs rename to Components/Custom/LockedChoice.cs index c8f6b47..9f66910 100644 --- a/Components/Nodes/LockedChoice.cs +++ b/Components/Custom/LockedChoice.cs @@ -1,9 +1,11 @@ -using System; +// Please see https://omch.tech/descant/#lockedchoice for documentation + +using System; namespace DescantComponents { [Serializable, MaxQuantity(Single.PositiveInfinity), NodeType(DescantNodeType.Choice)] - public class LockedChoice : DescantNodeComponent + public class LockedChoice : DescantComponent { [Inline] public string ActorName; diff --git a/Components/Nodes/LockedChoice.cs.meta b/Components/Custom/LockedChoice.cs.meta similarity index 100% rename from Components/Nodes/LockedChoice.cs.meta rename to Components/Custom/LockedChoice.cs.meta diff --git a/Components/Nodes/Log.cs b/Components/Custom/Log.cs similarity index 75% rename from Components/Nodes/Log.cs rename to Components/Custom/Log.cs index 2762a10..4b145cb 100644 --- a/Components/Nodes/Log.cs +++ b/Components/Custom/Log.cs @@ -1,10 +1,12 @@ -using System; +// Please see https://omch.tech/descant/#log for documentation + +using System; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(float.PositiveInfinity), NodeType(DescantNodeType.Any)] - public class Log : DescantNodeComponent + public class Log : DescantComponent { [Inline] public string Message; diff --git a/Components/Nodes/Log.cs.meta b/Components/Custom/Log.cs.meta similarity index 100% rename from Components/Nodes/Log.cs.meta rename to Components/Custom/Log.cs.meta diff --git a/Components/Nodes/PortraitChange.cs b/Components/Custom/PortraitChange.cs similarity index 89% rename from Components/Nodes/PortraitChange.cs rename to Components/Custom/PortraitChange.cs index b26d916..589b469 100644 --- a/Components/Nodes/PortraitChange.cs +++ b/Components/Custom/PortraitChange.cs @@ -1,11 +1,11 @@ -using System; +// Please see https://omch.tech/descant/#portraitchange for documentation + +using System; namespace DescantComponents { - public enum PortraitChangeType { Set, Enable, Disable } - [Serializable, MaxQuantity(Single.PositiveInfinity), NodeType(DescantNodeType.Any)] - public class PortraitChange : DescantNodeComponent + public class PortraitChange : DescantComponent { [Inline] public bool PlayerPortrait; diff --git a/Components/Nodes/PortraitChange.cs.meta b/Components/Custom/PortraitChange.cs.meta similarity index 100% rename from Components/Nodes/PortraitChange.cs.meta rename to Components/Custom/PortraitChange.cs.meta diff --git a/Components/Nodes/RandomizedChoice.cs b/Components/Custom/RandomizedChoice.cs similarity index 79% rename from Components/Nodes/RandomizedChoice.cs rename to Components/Custom/RandomizedChoice.cs index 8432171..ff34d22 100644 --- a/Components/Nodes/RandomizedChoice.cs +++ b/Components/Custom/RandomizedChoice.cs @@ -1,11 +1,13 @@ -using System; +// Please see https://omch.tech/descant/#randomizedchoice for documentation + +using System; using System.Collections.Generic; using Random = UnityEngine.Random; namespace DescantComponents { [Serializable, MaxQuantity(1), NodeType(DescantNodeType.Choice)] - public class RandomizedChoice : DescantNodeComponent // TODO: make this always last + public class RandomizedChoice : DescantComponent // TODO: make this always last { public override DescantNodeInvokeResult Invoke(DescantNodeInvokeResult result) { diff --git a/Components/Nodes/RandomizedChoice.cs.meta b/Components/Custom/RandomizedChoice.cs.meta similarity index 100% rename from Components/Nodes/RandomizedChoice.cs.meta rename to Components/Custom/RandomizedChoice.cs.meta diff --git a/Components/Nodes/RelationshipChange.cs b/Components/Custom/RelationshipChange.cs similarity index 91% rename from Components/Nodes/RelationshipChange.cs rename to Components/Custom/RelationshipChange.cs index f7e72d0..c6b824b 100644 --- a/Components/Nodes/RelationshipChange.cs +++ b/Components/Custom/RelationshipChange.cs @@ -1,9 +1,11 @@ -using System; +// Please see https://omch.tech/descant/#relationshipchange for documentation + +using System; namespace DescantComponents { [Serializable, MaxQuantity(Single.PositiveInfinity), NodeType(DescantNodeType.Any)] - public class RelationshipChange : DescantNodeComponent + public class RelationshipChange : DescantComponent { [ParameterGroup("Actors")] public string FirstActorName; [ParameterGroup("Actors")] public string SecondActorName; diff --git a/Components/Nodes/RelationshipChange.cs.meta b/Components/Custom/RelationshipChange.cs.meta similarity index 100% rename from Components/Nodes/RelationshipChange.cs.meta rename to Components/Custom/RelationshipChange.cs.meta diff --git a/Components/Nodes/StatisticChange.cs b/Components/Custom/StatisticChange.cs similarity index 90% rename from Components/Nodes/StatisticChange.cs rename to Components/Custom/StatisticChange.cs index fb5edf3..10f14f7 100644 --- a/Components/Nodes/StatisticChange.cs +++ b/Components/Custom/StatisticChange.cs @@ -1,9 +1,11 @@ -using System; +// Please see https://omch.tech/descant/#statisticchange for documentation + +using System; namespace DescantComponents { [Serializable, MaxQuantity(Single.PositiveInfinity), NodeType(DescantNodeType.Any)] - public class StatisticChange : DescantNodeComponent + public class StatisticChange : DescantComponent { [Inline] public string ActorName; diff --git a/Components/Nodes/StatisticChange.cs.meta b/Components/Custom/StatisticChange.cs.meta similarity index 100% rename from Components/Nodes/StatisticChange.cs.meta rename to Components/Custom/StatisticChange.cs.meta diff --git a/Components/Nodes/StatisticReveal.cs b/Components/Custom/StatisticReveal.cs similarity index 89% rename from Components/Nodes/StatisticReveal.cs rename to Components/Custom/StatisticReveal.cs index eaaaea7..479beda 100644 --- a/Components/Nodes/StatisticReveal.cs +++ b/Components/Custom/StatisticReveal.cs @@ -1,10 +1,12 @@ -using System; +// Please see https://omch.tech/descant/#statisticreveal for documentation + +using System; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(Single.PositiveInfinity), NodeType(DescantNodeType.Any)] - public class StatisticReveal : DescantNodeComponent + public class StatisticReveal : DescantComponent { [Inline] public string ActorName; diff --git a/Components/Nodes/StatisticReveal.cs.meta b/Components/Custom/StatisticReveal.cs.meta similarity index 100% rename from Components/Nodes/StatisticReveal.cs.meta rename to Components/Custom/StatisticReveal.cs.meta diff --git a/Components/Nodes/TimedChoice.cs b/Components/Custom/TimedChoice.cs similarity index 93% rename from Components/Nodes/TimedChoice.cs rename to Components/Custom/TimedChoice.cs index 72add1f..c5c2f51 100644 --- a/Components/Nodes/TimedChoice.cs +++ b/Components/Custom/TimedChoice.cs @@ -1,10 +1,12 @@ -using System; +// Please see https://omch.tech/descant/#timedchoice for documentation + +using System; using UnityEngine; namespace DescantComponents { [Serializable, MaxQuantity(1), NodeType(DescantNodeType.Choice)] - public class TimedChoice : DescantNodeComponent + public class TimedChoice : DescantComponent { [Inline] public float Time; diff --git a/Components/Nodes/TimedChoice.cs.meta b/Components/Custom/TimedChoice.cs.meta similarity index 100% rename from Components/Nodes/TimedChoice.cs.meta rename to Components/Custom/TimedChoice.cs.meta diff --git a/Components/Nodes/TopicChange.cs b/Components/Custom/TopicChange.cs similarity index 88% rename from Components/Nodes/TopicChange.cs rename to Components/Custom/TopicChange.cs index 45f0c9e..11bbed1 100644 --- a/Components/Nodes/TopicChange.cs +++ b/Components/Custom/TopicChange.cs @@ -1,9 +1,11 @@ -using System; +// Please see https://omch.tech/descant/#topicchange for documentation + +using System; namespace DescantComponents { [Serializable, MaxQuantity(Single.PositiveInfinity), NodeType(DescantNodeType.Response)] - public class TopicChange : DescantNodeComponent + public class TopicChange : DescantComponent { [Inline] public string ActorName; diff --git a/Components/Nodes/TopicChange.cs.meta b/Components/Custom/TopicChange.cs.meta similarity index 100% rename from Components/Nodes/TopicChange.cs.meta rename to Components/Custom/TopicChange.cs.meta diff --git a/Components/DescantActor.cs b/Components/DescantActor.cs index bc9d37a..81fabc0 100644 --- a/Components/DescantActor.cs +++ b/Components/DescantActor.cs @@ -1,31 +1,71 @@ using System; using System.Collections.Generic; -using UnityEngine.Serialization; namespace DescantComponents { + /// + /// A data class representing an actor (player or NPC) in a Descant Dialogue + /// [Serializable] public class DescantActor { + /// + /// The name of the actor + /// public string Name; + + /// + /// The local path to the file after the Assets folder + /// (useful for knowing where to save the file when no longer in its directory) + /// public string Path; + /// + /// The actor's statistics dictionary keys + /// (C# Dictionaries can't be [Serialized], so we use two Lists instead) + /// public List StatisticKeys; + + /// + /// The actor's statistics dictionary values + /// (C# Dictionaries can't be [Serialized], so we use two Lists instead) + /// public List StatisticValues; + /// + /// The actor's topics list + /// public List Topics; + /// + /// The actor's relationships dictionary keys + /// (C# Dictionaries can't be [Serialized], so we use two Lists instead) + /// public List RelationshipKeys; + + /// + /// The actor's relationships dictionary values + /// (C# Dictionaries can't be [Serialized], so we use two Lists instead) + /// public List RelationshipValues; + /// + /// The number of times that the player has attempted to start a dialogue with the actor + /// public int DialogueAttempts; - + + /// + /// Parameterized constructor + /// (most of the DescantActor's properties are set after + /// it has been initialized, as part of the saving process) + /// + /// The name of the actor public DescantActor(string name) { #if UNITY_EDITOR - Name = DescantUtilities.FilterText(name); + Name = DescantUtilities.FilterText(name); #else - Name = name; + Name = name; #endif StatisticKeys = new List(); @@ -37,6 +77,9 @@ public DescantActor(string name) RelationshipValues = new List(); } + /// + /// Overridden ToString method + /// public override string ToString() { string statistics = ""; diff --git a/Components/DescantComponent.cs b/Components/DescantComponent.cs new file mode 100644 index 0000000..37b5a68 --- /dev/null +++ b/Components/DescantComponent.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; + +namespace DescantComponents +{ + /// + /// Descant node Component parent class + /// + [Serializable] + public abstract class DescantComponent + { + /// + /// Whether this Component is currently collapsed in the UI + /// + public bool Collapsed; + + /// + /// Called when the node to which this Component is attached is reached in the dialogue + /// + /// The state of the text, actors, and portraits when the Component is Invoked + /// The state of the text, actors, and portraits after the Component is Invoked + public virtual DescantNodeInvokeResult Invoke(DescantNodeInvokeResult result) + { + return result; + } + + /// + /// Called when FixedUpdate occurs in the DescantDialogueController + /// + /// Whether or not to stop the dialogue immediately + public virtual bool FixedUpdate() + { + return true; + } + + /// + /// Called when Update occurs in the DescantDialogueController + /// + /// Whether or not to stop the dialogue immediately + public virtual bool Update() + { + return true; + } + + /// + /// Quickly compares two float values based on some comparison type + /// + /// The main variable in question + /// The value itr is being compared against + /// How the values are being compared + /// Whether the comparison succeeds or not + protected static bool CompareVariable(float variable, float comparison, ComparisonType comparisonType) + { + switch (comparisonType) + { + case ComparisonType.LessThan: + return variable < comparison; + + case ComparisonType.LessThanOrEqualTo: + return variable <= comparison; + + case ComparisonType.EqualTo: + return variable == comparison; + + case ComparisonType.GreaterThanOrEqualTo: + return variable >= comparison; + + case ComparisonType.GreaterThan: + return variable > comparison; + + case ComparisonType.NotEqualTo: + return variable != comparison; + + default: return false; + } + } + + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one + public override bool Equals(object other) + { + try + { + _ = (DescantComponent) other; + } + catch + { + return false; + } + + return Equals((DescantComponent)other); + } + + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantComponent has the same data as this one + public bool Equals(DescantComponent other) + { + return ToString().Equals(other.ToString()); + } + + /// + /// Overridden ToString method + /// + public override string ToString() + { + string temp = ""; + + foreach (var i in GetType().GetFields()) + temp += " " + i.GetValue(this); + + return GetType() + " (" + (temp.Length > 1 ? temp.Substring(1) : "") + ")"; + } + } + + /// + /// A DescantNode class attribute to indicate the maximum number of + /// Components of the attached type that can be added to a DescantNode + /// + public class MaxQuantityAttribute : Attribute + { + public readonly float Quantity; + + public MaxQuantityAttribute(float quantity) => Quantity = quantity; + } + + /// + /// A DescantNode class attribute to indicate which type(s) of DescantNodes that the attached type can be added to + /// + public class NodeTypeAttribute : Attribute + { + public readonly DescantNodeType Type; + + public NodeTypeAttribute(DescantNodeType type) => Type = type; + } + + /// + /// A DescantNode property attribute to indicate that the attached parameter + /// should be rendered inline with the name in the Descant Graph GUI + /// + public class InlineAttribute : Attribute { } + + /// + /// A DescantNode property attribute to indicate to which group/row + /// the attached parameter should be rendered in the Descant Graph GUI + /// + public class ParameterGroupAttribute : Attribute + { + public readonly string Group; + + public ParameterGroupAttribute(string group) => Group = group; + } + + /// + /// A DescantNode property attribute to indicate that the attached + /// parameter should not be filtered in the Descant Graph GUI + /// + public class NoFilteringAttribute : Attribute { } +} \ No newline at end of file diff --git a/Components/DescantNodeComponent.cs.meta b/Components/DescantComponent.cs.meta similarity index 100% rename from Components/DescantNodeComponent.cs.meta rename to Components/DescantComponent.cs.meta diff --git a/Components/DescantComponentUtilities.cs b/Components/DescantComponentUtilities.cs index 3b46d7e..0b7aef0 100644 --- a/Components/DescantComponentUtilities.cs +++ b/Components/DescantComponentUtilities.cs @@ -8,31 +8,53 @@ namespace DescantComponents { public static class DescantComponentUtilities { - public static List GetAllNodeComponentTypes() + #region Component Type Lists + + /// + /// Gets the list of all class types that inherit from DescantComponent + /// + public static List GetComponentTypes() { return AppDomain.CurrentDomain.GetAssemblies() .SelectMany(domainAssembly => domainAssembly.GetTypes()) - .Where(type => type.IsSubclassOf(typeof(DescantNodeComponent))) + .Where(type => type.IsSubclassOf(typeof(DescantComponent))) .ToList(); } - - public static string GetTrimmedNodeComponentType(Type type) + + /// + /// Trims a class name down to its base name (i.e. not including namespaces/parents) + /// + /// The type with the name to be trimmed + public static string GetTrimmedTypeName(Type type) { - return type.ToString().Substring(18); + var temp = type.ToString(); + return temp.Substring(temp.LastIndexOf('.') + 1); } - public static List TrimmedNodeComponentTypes(List types) + /// + /// Gets the list of trimmed names of all class types that inherit from DescantComponent + /// + /// The types with names to be trimmed + /// + public static List GetTrimmedComponentTypes(List types) { return types - .Select(GetTrimmedNodeComponentType) + .Select(GetTrimmedTypeName) .ToList(); } - - public static float GetNodeComponentMaximum(string componentName) + + #endregion + + #region Component Attributes + + /// + /// Gets the maximum number of Components of some type that can be added to a DescantNode + /// + /// The name of the Component being checked + /// (-1 if no maximum has been indicated) + public static float GetComponentMaximum(string componentName) { - List types = GetAllNodeComponentTypes(); - - foreach (var i in types) + foreach (var i in GetComponentTypes()) { string typeName = i.ToString().Substring(i.ToString().LastIndexOf('.') + 1); @@ -48,30 +70,41 @@ public static float GetNodeComponentMaximum(string componentName) return -1; } + /// + /// Gets the value of a Component's parameter, making sure to first parse it accordingly + /// + /// The value of the parameter + /// The type of the parameter public static object GetComponentParameterValue(string value, Type type) { - object temp = type != typeof(string) - ? float.Parse(value) - : value; - - return type == typeof(int) - ? int.Parse(value) - : temp; + if (type == typeof(int)) return float.Parse(value); + if (type == typeof(float)) return float.Parse(value); + return value; } - public static bool InvokeMethod( - DescantNodeComponent component, + #endregion + + #region Method Invokation + + /// + /// Calls a method from somewhere in the scene + /// + /// The Component source that this call is coming from + /// The script that the method belongs to + /// The name of the script that the method belongs to + /// The name of the method being called + /// The parameter being accepted by the method (can be empty) + /// Whether the method was successfully called + static bool InvokeMethod( + DescantComponent component, MonoBehaviour script, string scriptName, string methodName, string parameter) { - if (scriptName == "" || methodName == "") return false; + if (scriptName == "" || methodName == "") return false; // Stopping if the script or method names are false - string fullType = script.GetType().ToString(); - string type = fullType.Substring(fullType.LastIndexOf('.') + 1); - - if (type == scriptName) + if (GetTrimmedTypeName(script.GetType()) == scriptName) { try { @@ -87,7 +120,9 @@ public static bool InvokeMethod( return false; } - if (method.GetParameters().Length == 0) + var methodParameters = method.GetParameters(); // The ParameterInfo for the method + + if (methodParameters.Length > 1) { DescantUtilities.ErrorMessage( component.GetType(), @@ -97,9 +132,9 @@ public static bool InvokeMethod( return false; } - List parameters = new List(); + List parameters = new List(); // The parameters that are going to be supplied - foreach (var j in method.GetParameters()) + foreach (var j in methodParameters) parameters.Add(GetComponentParameterValue( parameter, j.ParameterType @@ -121,8 +156,20 @@ public static bool InvokeMethod( return false; } + /// + /// Calls a method from somewhere in the scene + /// + /// The Component source that this call is coming from + /// + /// The tag of the GameObject that the script is attached to + /// (if empty, the first found script in the scene with the given name is called instead + /// + /// The name of the script that the method belongs to (if empty, no method is called) + /// The name of the method being called (if empty, no method is called) + /// The parameter being accepted by the method (can be empty) + /// Whether the method was successfully called public static bool InvokeFromObjectOrScript( - DescantNodeComponent component, + DescantComponent component, string objectTag, string scriptName, string methodName, @@ -143,16 +190,30 @@ public static bool InvokeFromObjectOrScript( return false; } - - public static void MissingMethodError(DescantNodeComponent component, string scriptName, string methodName) + + /// + /// Method to be called by Components if InvokeFromObjectOrScript returns false + /// + /// The Component source that this call is coming from + /// The name of the script that the method belongs to + /// The name of the method being called + public static void MissingMethodError(DescantComponent component, string scriptName, string methodName) { DescantUtilities.ErrorMessage( component.GetType(), "Unable to find method '" + methodName + "' on script '" + scriptName + "'!" ); } - - public static DescantActor GetActor(DescantNodeComponent component, List actors, string name) + + #endregion + + /// + /// Gets an actor with a given name from the a list of actors + /// + /// The Component source that this call is coming from + /// The current list of DescantActors + /// The name of the DescantActor being searched for + public static DescantActor GetActor(DescantComponent component, List actors, string name) { foreach (var i in actors) if (i.Name.Equals(name.Trim())) @@ -166,6 +227,12 @@ public static DescantActor GetActor(DescantNodeComponent component, List + /// Parses a string into an enum + /// + /// The string value to parse + /// The enum type we are checking + /// The value that the string corresponds to public static T ParseEnum(string value) where T : Enum { return (T)Enum.Parse(typeof(T), value, true); diff --git a/Components/DescantNodeComponent.cs b/Components/DescantNodeComponent.cs deleted file mode 100644 index 35b23d6..0000000 --- a/Components/DescantNodeComponent.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace DescantComponents -{ - public enum VariableType { Statistic, Topic, Relationship, DialogueAttempts } - public enum ComparisonType { LessThan, LessThanOrEqualTo, EqualTo, GreaterThanOrEqualTo, GreaterThan, NotEqualTo } - public enum OperationType { IncreaseBy, DecreaseBy, Set } - public enum ListChangeType { Add, Remove } - - public class DescantNodeInvokeResult - { - public List> Text; - public List Actors; - public string PlayerPortrait; - public bool PlayerPortraitEnabled; - public string NPCPortrait; - public bool NPCPortraitEnabled; - - public DescantNodeInvokeResult( - List> text, - List actors, - string playerPortrait, - bool playerPortraitEnabled, - string npcPortrait, - bool npcPortraitEnabled) - { - Text = text; - Actors = actors; - PlayerPortrait = playerPortrait; - PlayerPortraitEnabled = playerPortraitEnabled; - NPCPortrait = npcPortrait; - NPCPortraitEnabled = npcPortraitEnabled; - } - } - - [Serializable] - public abstract class DescantNodeComponent - { - public bool Collapsed; - - public virtual DescantNodeInvokeResult Invoke(DescantNodeInvokeResult result) - { - return result; - } - - public virtual bool FixedUpdate() - { - return true; - } - - public virtual bool Update() - { - return true; - } - - public override bool Equals(object other) - { - try - { - var unused = (DescantNodeComponent) other; - } - catch - { - return false; - } - - return Equals((DescantNodeComponent)other); - } - - public bool Equals(DescantNodeComponent other) - { - return ToString().Equals(other.ToString()); - } - - protected static bool CompareVariable(float variable, float comparison, ComparisonType comparisonType) - { - switch (comparisonType) - { - case ComparisonType.LessThan: - return variable < comparison; - - case ComparisonType.LessThanOrEqualTo: - return variable <= comparison; - - case ComparisonType.EqualTo: - return variable == comparison; - - case ComparisonType.GreaterThanOrEqualTo: - return variable >= comparison; - - case ComparisonType.GreaterThan: - return variable > comparison; - - case ComparisonType.NotEqualTo: - return variable != comparison; - - default: return false; - } - } - - public override string ToString() - { - string temp = ""; - - foreach (var i in GetType().GetFields()) - temp += " " + i.GetValue(this); - - return GetType() + " (" + (temp.Length > 1 ? temp.Substring(1) : "") + ")"; - } - } - - public class MaxQuantityAttribute : Attribute - { - public readonly float Quantity; - - public MaxQuantityAttribute(float quantity) => Quantity = quantity; - } - - public class NodeTypeAttribute : Attribute - { - public readonly DescantNodeType Type; - - public NodeTypeAttribute(DescantNodeType type) => Type = type; - } - - public class InlineAttribute : Attribute { } - - public class ParameterGroupAttribute : Attribute - { - public readonly string Group; - - public ParameterGroupAttribute(string group) => Group = group; - } - - public class NoFilteringAttribute : Attribute { } -} \ No newline at end of file diff --git a/Components/DescantNodeInvokeResult.cs b/Components/DescantNodeInvokeResult.cs new file mode 100644 index 0000000..b040f68 --- /dev/null +++ b/Components/DescantNodeInvokeResult.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; + +namespace DescantComponents +{ + /// + /// Enum of DescantActors' variable types + /// (used by DescantComponents when querying such variables) + /// + public enum VariableType { Statistic, Topic, Relationship, DialogueAttempts } + + /// + /// Enum of different ways to compare DescantActors' variables + /// (used by DescantComponents when querying such variables) + /// + public enum ComparisonType { LessThan, LessThanOrEqualTo, EqualTo, GreaterThanOrEqualTo, GreaterThan, NotEqualTo } + + /// + /// Enum of ways to perform operations upon DescantActors' variables + /// (used by DescantComponents when querying such variables) + /// + public enum OperationType { IncreaseBy, DecreaseBy, Set } + + /// + /// Enum ways to perform operations upon DescantActors' lists/dictionaries + /// (used by DescantComponents when querying such lists) + /// + public enum ListChangeType { Add, Remove } + + /// + /// Enum of ways to perform operations upon DescantActors' portraits + /// (used by DescantComponents when querying such portraits) + /// + public enum PortraitChangeType { Enable, Disable, Set } + + /// + /// Data class all the choice/response text for the current node, + /// the current actors, and info regarding the actor portraits + /// + public class DescantNodeInvokeResult + { + /// + /// The list of texts to display for the current node (as well index for their position when displayed) + /// + public List> Text; + + /// + /// The list of current DescantActors + /// + public List Actors; + + /// + /// The current name of the player's portrait + /// + public string PlayerPortrait; + + /// + /// Whether the player's portrait is currently enabled + /// + public bool PlayerPortraitEnabled; + + /// + /// The current name of the NPC's portrait + /// + public string NPCPortrait; + + /// + /// Whether the NPC's portrait is currently enabled + /// + public bool NPCPortraitEnabled; + + /// + /// Parameterized constructor + /// + /// + /// The list of texts to display for the current node (as well index for their position when displayed) + /// + /// The list of current DescantActors + /// The current name of the player's portrait + /// Whether the player's portrait is currently enabled + /// The current name of the NPC's portrait + /// Whether the NPC's portrait is currently enabled + public DescantNodeInvokeResult( + List> text, + List actors, + string playerPortrait, + bool playerPortraitEnabled, + string npcPortrait, + bool npcPortraitEnabled) + { + Text = text; + Actors = actors; + PlayerPortrait = playerPortrait; + PlayerPortraitEnabled = playerPortraitEnabled; + NPCPortrait = npcPortrait; + NPCPortraitEnabled = npcPortraitEnabled; + } + } +} \ No newline at end of file diff --git a/Components/DescantNodeInvokeResult.cs.meta b/Components/DescantNodeInvokeResult.cs.meta new file mode 100644 index 0000000..e72b13c --- /dev/null +++ b/Components/DescantNodeInvokeResult.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8f88d02a509646c59bd7c3fd49be357f +timeCreated: 1703627418 \ No newline at end of file diff --git a/Documentation/Website.meta b/Documentation/Website.meta new file mode 100644 index 0000000..5e05b32 --- /dev/null +++ b/Documentation/Website.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c1a317978e8d46c5968a1c7aae141323 +timeCreated: 1703632683 \ No newline at end of file diff --git a/Documentation/Website/components.js b/Documentation/Website/components.js new file mode 100644 index 0000000..901b132 --- /dev/null +++ b/Documentation/Website/components.js @@ -0,0 +1,200 @@ +let components = [ + [ + 'ChangedChoice', 'None', 'Choice', + 'Changes the text of one of a ChoiceNode\'s choices if some condition is met.', + [ + 'ActorName', 'The name the actor who\'s variable is being checked', + 'ChoiceNumber', 'The index of the choice being changed (base 1)', + 'VariableType', 'The type of the variable being checked (e.g. Statistic, ' + + 'Topic, etc.)', + 'VariableName', 'The name of the variable being checked', + 'ComparisonType', 'The type of the comparison being performed against the variable', + 'Comparison', 'The value to compare the variable against', + 'ChangeTo', 'The text to change the choice to if the comparison succeeds', + ] + ], + [ + 'ChangedResponse', 'None', 'Response', + 'Changes the text of a ResponseNode\'s response if some condition is met.', + [ + 'ActorName', 'The name the actor who\'s variable is being checking', + 'VariableType', 'The type of the variable being checked (e.g. Statistic, ' + + 'Topic, etc.)', + 'VariableName', 'The name of the variable being checked', + 'ComparisonType', 'The type of the comparison being performed against the variable', + 'Comparison', 'The value to compare the variable against', + 'ChangeTo', 'The text to change the choice to if the comparison succeeds', + ] + ], + [ + 'Event', 'None', 'Any', + 'Calls a method from a script.', + [ + 'ObjectTag', 'The tag of the GameObject on which the script is located (optional)', + 'ScriptName', 'The name of the script on the GameObject', + 'MethodName', 'The name of the method being called', + 'Parameter', 'The parameter to pass to the method (optional)', + ], + 'If ObjectTag is empty, the first found script in the scene ' + + 'with the given name is called instead.

If the ScriptName or MethodName ' + + 'are empty, no method is called.

While Parameter is technically of type ' + + 'string, Integers and Floats can also be written, and ' + + 'will be parsed accordingly.

Currently, methods with more than one parameter cannot be called.' + ], + [ + 'Interruptable', 'None', 'Response', + 'Allows for the dialogue to be abruptly stopped with a key or button press. Once this happens, a method ' + + 'from a script can be called.', + [ + 'KeyCode', 'The lowercase name of the key press to check for (e.g. "e", "space", etc.) (optional)', + 'ButtonName', 'The name of the button press to check for (e.g. "Fire1", etc.) (optional)', + 'ObjectTag', 'The tag of the GameObject on which the script is located (optional)', + 'ScriptName', 'The name of the script on the GameObject (optional)', + 'MethodName', 'The name of the method being called (optional)', + 'Parameter', 'The parameter to pass to the method (optional)', + ], + 'If ObjectTag is empty, the first found script in the scene ' + + 'with the given name is called instead.

If the ScriptName or MethodName ' + + 'are empty, no method is called.

While Parameter is technically of type ' + + 'string, Integers and Floats can also be written, and ' + + 'will be parsed accordingly.

Currently, methods with more than one parameter cannot be called.' + ], + [ + 'LockedChoice', 'None', 'Choice', + 'Removes one of a ChoiceNode\'s choices if some condition is met.', + [ + 'ActorName', 'The name the actor who\'s variable is being checked', + 'ChoiceNumber', 'The index of the choice being removed (base 1)', + 'VariableType', 'The type of the variable being checked (e.g. Statistic, ' + + 'Topic, etc.)', + 'VariableName', 'The name of the variable being checked', + 'ComparisonType', 'The type of the comparison being performed against the variable', + 'Comparison', 'The value to compare the variable against', + ] + ], + [ + 'Log', 'None', 'Any', + 'Prints a Debug.Log to the console.', + [ + 'Message', 'The message to log', + ] + ], + [ + 'PortraitChange', 'None', 'Any', + 'Changes and actor\'s portrait.', + [ + 'PlayerPortrait', 'Whether the portrait being changed is the player\'s or the NPC\'s.', + 'ChangeType', 'The change being made to the portrait (set, enabled, or disabled)', + 'PortraitName', 'The name of the new portrait to be set (optional)', + ], + 'For a portrait to be set, a Sprite with the corresponding name must be passed into the ' + + 'DescantDialogueTrigger\'s portrait property.' + ], + [ + 'RandomizedChoice', '1', 'Choice', + 'Randomizes/shuffles a ChoiceNode\'s choices.', + [], + 'As a best practice, always make sure you only add this Component to a node after all other ' + + 'Components have been added to that node (especially after ones that affect a specific choice).' + ], + [ + 'RelationshipChange', 'None', 'Any', + 'Changes one of an actor\'s relationships.', + [ + 'FirstActorName', 'The name of the actor who\'s relationship is being changed', + 'SecondActorName', 'The name of the actor that the relationship corresponds to', + 'OperationType', 'The change being made to the relationship (increase, decrease, or set)', + 'OperationValue', 'The value to change the relationship by', + ], + 'Changing the first actor\'s relationship to the second will not change the second\'s relationship ' + + 'to the first.' + ], + [ + 'StatisticChange', 'None', 'Any', + 'Changes an one of actor\'s statistics.', + [ + 'ActorName', 'The name the actor who\'s statistic is being changed', + 'StatisticName', 'The name of the statistic being changed', + 'OperationType', 'The change being made to the statistic (increase, decrease, or set)', + 'OperationValue', 'The value to change the statistic by', + ] + ], + [ + 'StatisticReveal', 'None', 'Any', + 'Calls a method from a script, passing it an actor\'s statistic (e.g. to display how an NPC\'s mood might ' + + 'increase/decrease during a dialogue).', + [ + 'ActorName', 'The name the actor who\'s variable is being revealed', + 'StatisticName', 'The name of the statistic being revealed', + 'ObjectTag', 'The tag of the GameObject on which the script is located (optional)', + 'ScriptName', 'The name of the script on the GameObject', + 'MethodName', 'The name of the method being called', + ], + 'If ObjectTag is empty, the first found script in the scene ' + + 'with the given name is called instead.

If the ScriptName or MethodName ' + + 'are empty, no method is called.

Currently, methods with more than one parameter cannot be called.' + ], + [ + 'TimedChoice', '1', 'Choice', + 'Imposes a time restriction for choosing a TimedChoice\'s choice. Each FixedUpdate frame that the time is ' + + 'counting down, a method from a script can be called, passing the timer completion percentage (e.g. to ' + + 'update a timer UI). When the time reaches 0, a choice is automatically made, and another method can be ' + + 'called (e.g. to initiate a point penalty).', + [ + 'Time', 'The amount of time the player has to choose (in seconds)', + 'ChoiceToPick', 'The index of the choice to pick if the timer runs out (base 1)', + 'ObjectTag', 'The tag of the GameObject on which the script is located (optional)', + 'ScriptName', 'The name of the script on the GameObject', + 'TimerMethodName', 'The name of the method called while the timer is counting down (optional)', + 'FinishedMethodName', 'The name of the method called when the timer reaches 0 (optional)', + ], + 'If ObjectTag is empty, the first found script in the scene ' + + 'with the given name is called instead.

If the ScriptName is empty, no method is ' + + 'called. If TimerMethodName is empty, it isn\'t called. If FinishedMethodName ' + + 'is empty, it isn\'t called.

Currently, methods with more than one parameter cannot be called.' + ], + [ + 'TopicChange', 'None', 'Response', + 'Changes one of an actor\'s topics.', + [ + 'ActorName', 'The name the actor who\'s topic is being changed', + 'TopicName', 'The name of the topic being changed', + 'ChangeType', 'The change being made to the topic (add or remove)', + ] + ], +]; + +window.onload = function () { + let components_parent = document.getElementById('components'); + + for (let i in components) { + let component = document.createElement('div'); + component.setAttribute('class', 'flex column start component'); + component.id = components[i][0].toLowerCase(); + components_parent.appendChild(component); + + let variables = ''; + + for (let j = 0; j < components[i][4].length; j++) + if (j % 2 === 0) variables += '

' + components[i][4][j] + ': ' + components[i][4][j + 1] + '

'; + + component.innerHTML = + '

' + components[i][0] + '

' + + '

' + components[i][3] + '

' + + '

Max Quantity: ' + components[i][1] + '

' + + '

Node Type(s): ' + components[i][2] + '

' + + (components[i][4].length === 0 ? '' : ('

Variables:

' + variables)) + + (components[i].length < 6 ? '' + : '

Disclaimers:

' + components[i][5] + '

'); + } + + let anchors = document.querySelectorAll('a'); + + for (const j in anchors) { + try { + anchors[j].setAttribute('rel', 'noreferrer noopener'); + anchors[j].setAttribute('target', '_blank'); + } + catch { } + } +}; \ No newline at end of file diff --git a/Documentation/Website/components.js.meta b/Documentation/Website/components.js.meta new file mode 100644 index 0000000..d23dee6 --- /dev/null +++ b/Documentation/Website/components.js.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f4efc40ca0744998b161aa96e0052d6 +timeCreated: 1703632699 \ No newline at end of file diff --git a/Documentation/Website/index.html b/Documentation/Website/index.html new file mode 100644 index 0000000..1a190df --- /dev/null +++ b/Documentation/Website/index.html @@ -0,0 +1,150 @@ + + + + + Descant - Enhanced Unity Dialogue System + + + + + + + + + + + + + + + + + + + + + + +
+
+

Descant

+

Enhanced Unity Dialogue System

+

by Owen Hellum

+
+ +
+

+ Please view the Descant README for + information regarding installation and usage! +

+
+ + + +
+

+ Descant is a Unity dialogue system plugin. The + Unity Asset Store is + chock full of many such + types of plugins, ranging from feature-rich, + to ultra-minimalist, + to downright bad. + Descant aims to hit the sweet spot between quality UI, powerful features, and easy-to-lean + functionality, while also addressing many of the game-specific consequences of the standard dialogue manager + setup. Besides acting as a standard tool for creating, saving, and actualizing non-linear game dialogue, it + also pushes the envelope by adding optional dialogue-enhancing node components that introduce features to break + away from the overused and underwhelming trends seen in many interactive fiction games. These enhancements act + similar to Unity's standard GameObject Component system, and can be applied + at-will to nodes. This modular approach is so-far not explored in the world of Unity dialogue systems. The + project will be free (and collaborative open-source) forever. Feel free to send me a message or submit + a pull request if you want to make any changes. +

+
+ +
+

Component documentation

+

+ A number of Descant Components come bundled with the system by default. They cover a wide range of + applications, and can be edited at-will. Please see the next section, Component creation, for + a guide on how to write your own Components in C#. +

+ +
+
+ +
+

Component creation

+
    +
  1. Create a new C# class in Descant/Components/Custom.
  2. +
  3. Make sure that the Component is in the DescantComponents namespace.
  4. +
  5. Make sure that the Component inherits from the DescantComponent abstract class.
  6. +
  7. Add a [Serializable] attribute to the Component.
  8. +
  9. + Add a [MaxQuantity(...)] attribute to the Component (replace the '...' with the maximum number + of Components of this type that can be added to a single node) ('...' can be float.PositiveInfinity). +
  10. +
  11. + Add a [NodeType(...)] attribute to the Component (replace the '...' with the + DescantNodeType indicating which types of nodes it can be added to). +
  12. +
  13. + Add any number of public variables/properties to the Component (these properties will show up in + the Descant Graph Editor when you add the Component to a node) (you may also create + private/protected properties, but they won't appear in the editor). Properties may only be of type + int, float, string, bool, or + enum (VariableType, ComparisonType, + OperationType, or ListChangeType enums only). +
  14. +
  15. + For each public variable, add either an [Inline] attribute (indicating that it will be + visually nestled beside the Component name in the editor) or a [ParameterGroup(...)] + attribute (indicating that it will be visually arranged in a new group beneath the Component name in the + editor) (replace the '...' with the string name of the group to order it into). +
  16. +
  17. + Optional: By default, all Component fields filter any out most special characters on input. You can + override this by giving any public variable a [NoFiltering] attribute, disabling filtering + for that variable's corresponding field in the Descant Graph Editor. This is useful for + long-form fields that may have sentence grammar and punctuation. +
  18. +
  19. + If this Component performs some action when it is reached during dialogue, give it the following method: + public override DescantNodeInvokeResult Invoke(DescantNodeInvokeResult result). The + DescantNodeInvokeResult object being passed contains all the choice/response text for the + current node, the current actors, and info regarding the actor portraits) (see the + DescantNodeInvokeResult + class for more info). The Invoke method must return a DescantNodeInvokeResult + object (almost always just result itself, with its properties modified). +
  20. +
  21. + Optional: Many of the default Components require actor names to know which actors' properties to check. + If your Component must also access a DescantActor, make sure that it has a public + string ActorName variable, then get access to the actor with + DescantComponentUtilities.GetActor(this, result.Actors, ActorName). +
  22. +
  23. + Optional: Many default Descant Components only do their effect if some comparison is made. Should your + Component also wish to do so, the CompareVariable method in + DescantComponent + may be of use. +
  24. +
  25. + Optional: If you need the Component to do something continuously while it is active during dialogue, give + it one of the following methods: public override bool FixedUpdate() or public + override bool Update(). They function in exactly the same manner as the classic MonoBehaviour + methods of the same names, save for the fact that if they ever return false, the dialogue + ends immediately (should the Component want to end the dialogue for some reason). +
  26. +
  27. + That's it! Your new Component will now show up as an option to add to a node in the Descant Graph + Editor. +
  28. +
+
+
+ + + \ No newline at end of file diff --git a/Documentation/Website/index.html.meta b/Documentation/Website/index.html.meta new file mode 100644 index 0000000..75fa60f --- /dev/null +++ b/Documentation/Website/index.html.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 100b742dd43d4fc7b8dddf7507b64a2a +timeCreated: 1703632699 \ No newline at end of file diff --git a/Documentation/Website/style.css b/Documentation/Website/style.css new file mode 100644 index 0000000..2eeae61 --- /dev/null +++ b/Documentation/Website/style.css @@ -0,0 +1,124 @@ +:root { + --descant-color-background: #2b2b2b; + --descant-color-default: rgba(51, 51, 51, 0.4); + --descant-color-light: rgba(51, 51, 51, 1); + + --descant-color-text: rgb(157, 157, 157); + + --choice-highlight: lightskyblue; + --choice-background: rgba(90, 137, 166, 0.7); + + --response-highlight: darkgoldenrod; + --response-background: rgba(164, 123, 19, 0.7); + + --start-highlight: mediumseagreen; + --start-background: rgba(46, 134, 85, 0.7); + + --end-highlight: firebrick; + --end-background: rgba(121, 23, 23, 0.7); + + --unsaved: lightcoral; +} + + +/* Elements */ + +body { + font-family: 'Open Sans', sans-serif; + font-weight: 400; + + color: var(--descant-color-text); + + background: var(--descant-color-background); +} + +h1, h2, h3, p { margin: 0; } +h2, h3 strong { font-weight: 700; } + +h1 { + font-weight: 800; + font-size: 60px; + color: var(--response-highlight); +} + +h2 { + margin-bottom: 20px; + + font-size: 30px; + color: var(--start-highlight); +} + +h3 { + margin-bottom: 15px; + + font-size: 25px; + color: var(--start-background); +} + +p, li { font-size: 20px; } + +a { + color: var(--choice-highlight); +} +a:hover { + color: var(--choice-background); +} + +li { + margin-bottom: 15px; + + line-height: 30px; +} + + +/* Flex Classes */ + +.flex { display: flex; } + +.column { flex-direction: column; } +.row { flex-direction: row; flex-wrap: wrap; } + +.start, .align_start { align-items: start; } +.center, .align_center { align-items: center; } +.end, .align_end { align-items: end; } + +.start, .justify_start { justify-content: start; } +.center, .justify_center { justify-content: center; } +.end, .justify_end { justify-content: end; } + + +/* Classes */ + +.section { + margin: 20px; +} + +.important { + padding: 20px; + + border-radius: 10px; + + color: var(--end-highlight); + + background: black; +} + +.component { + width: 100%; + + margin: 10px; + padding: 15px; + + border-radius: 10px; + + background: var(--descant-color-light); +} +.component p { + margin: 8px; +} + +/* IDs */ + +#content { width: 90%; } + +#components { margin-top: 20px; } \ No newline at end of file diff --git a/Documentation/Website/style.css.meta b/Documentation/Website/style.css.meta new file mode 100644 index 0000000..45221ab --- /dev/null +++ b/Documentation/Website/style.css.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bd89a17e11df4534a0f2b219a2d9332d +timeCreated: 1703632699 \ No newline at end of file diff --git a/Documentation/planning.meta b/Documentation/planning.meta deleted file mode 100644 index 2db7f2f..0000000 --- a/Documentation/planning.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: fe671ce95e650411c94b18fa3d98b8b2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Documentation/todo.md b/Documentation/todo.md index da57f06..dc87fbc 100644 --- a/Documentation/todo.md +++ b/Documentation/todo.md @@ -1,6 +1,6 @@ ## Easy -- Add comments +- ~~Add comments~~ - ~~Remove text filtering from certain Component fields~~ - ~~Round floats when saving to file~~ - ~~Update `README`~~ @@ -15,7 +15,6 @@ - ~~Make TMP text styling more intuitive when being typed out~~ - ~~Make it so that new nodes spawn where clicked~~ - ~~Fix bug with TimedChoice~~ -- Save panned position in `Descant Graph Editor` - ~~Add option to interject variables into the text~~ @@ -27,4 +26,6 @@ - ~~Make script calling easier~~ - Make autosave better (removed temporarily) - Create log system -- ~~Create an online Component documentation website~~ \ No newline at end of file +- ~~Create an online Component documentation website~~ +- Ctrl-S saving functionality for editors +- Save panned position in `Descant Graph Editor` \ No newline at end of file diff --git a/Editor/Data/DescantGraphData.cs b/Editor/Data/DescantGraphData.cs index 291d2b4..c6f7202 100644 --- a/Editor/Data/DescantGraphData.cs +++ b/Editor/Data/DescantGraphData.cs @@ -12,6 +12,9 @@ namespace DescantEditor [Serializable] public class DescantGraphData { + /// + /// The name of the Descant Graph + /// public string Name; /// @@ -21,33 +24,83 @@ public class DescantGraphData public string Path; /// - /// Whether to autosave this graph when in the Editor + /// Whether to autosave the graph when in the Editor /// public bool Autosave; + /// + /// Whether or not to type out ResponseNode text one character at a time + /// public bool Typewriter; + + /// + /// The speed of the typewriter (higher value = faster typing speed) + /// (see DescantDialogueUI::Type() for its application) + /// public float TypewriterSpeed; + /// + /// A unique ID number that will be applied to the next-created ChoiceNode + /// public int ChoiceNodeID; + + /// + /// A unique ID number that will be applied to the next-created ResponseNode + /// public int ResponseNodeID; + + /// + /// A unique ID number that will be applied to the next-created EndNode + /// public int EndNodeID; + + /// + /// A unique ID number that will be applied to the next-created NodeGroup + /// public int GroupID; + /// + /// The ChoiceNodes in the graph + /// public List ChoiceNodes; + + /// + /// The ResponseNodes in the graph + /// public List ResponseNodes; + + /// + /// The StartNode in the graph + /// public DescantStartNodeData StartNode; + + /// + /// The EndNodes in the graph + /// public List EndNodes; + /// + /// The NodeGroups in the graph + /// public List Groups; + /// + /// The connections between Nodes in the graph + /// public List Connections; + /// + /// Parameterized constructor + /// (most of the DescantGroupData's properties are set after + /// it has been initialized, as part of the saving process) + /// + /// The name of the Descant Graph public DescantGraphData(string name) { #if UNITY_EDITOR - Name = DescantUtilities.FilterText(name); + Name = DescantUtilities.FilterText(name); #else - Name = name; + Name = name; #endif Path = ""; @@ -56,17 +109,30 @@ public DescantGraphData(string name) TypewriterSpeed = 1; ChoiceNodes = new List(); ResponseNodes = new List(); - StartNode = new DescantStartNodeData("StartNode", "Start", Vector2.zero, new List()); + + // We assume that we'll replace this later, but just in case we don't, we create a default StartNode + StartNode = new DescantStartNodeData( + "StartNode", + "Start", + Vector2.zero, + new List() + ); + EndNodes = new List(); Groups = new List(); Connections = new List(); } + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one public override bool Equals(object other) { try { - var unused = (DescantGraphData) other; + _ = (DescantGraphData) other; } catch { @@ -76,11 +142,21 @@ public override bool Equals(object other) return Equals((DescantGraphData)other); } + #if UNITY_EDITOR + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantGraphData has the same data as this one public bool Equals(DescantGraphData other) { return ToString() == other.ToString(); } + #endif + /// + /// Overridden ToString method + /// public override string ToString() { string temp = ""; @@ -108,7 +184,7 @@ public override string ToString() (temp.Length > 1 ? temp : ""); } -#if UNITY_EDITOR + #if UNITY_EDITOR /// /// Saves all the data from this graph to its path /// @@ -125,7 +201,7 @@ public void Save(bool newFile) Application.dataPath + "/" + Path, DescantUtilities.FormatJSON(JsonUtility.ToJson(this))); } -#endif + #endif /// /// Loads and returns a new graph from a full disc path diff --git a/Editor/Data/DescantNodesData.cs b/Editor/Data/DescantNodesData.cs index 8e747e4..989e7f7 100644 --- a/Editor/Data/DescantNodesData.cs +++ b/Editor/Data/DescantNodesData.cs @@ -10,19 +10,47 @@ namespace DescantEditor /// public abstract class DescantNodeData { + /// + /// The custom name of the node + /// public string Name; + + /// + /// The unique identifier ID for the node + /// public string Type; + + /// + /// The type of this node + /// public int ID; + + /// + /// The node's current position + /// public Vector2 Position; - [SerializeReference] public List NodeComponents; + /// + /// The list of Components attached to the node + /// ([SerializeReference] is necessary to ensure that the Serialized + /// DescantNodeComponents are saved to the file as a list) + /// + [SerializeReference] public List NodeComponents; + /// + /// Parameterized constructor + /// + /// The custom name of the node + /// The unique identifier ID for the node + /// The type of this node + /// The node's current position + /// The list of Components attached to the node protected DescantNodeData( string name, string type, int id, Vector2 position, - List nodeComponents) + List nodeComponents) { Name = name; Type = type; @@ -31,11 +59,16 @@ protected DescantNodeData( NodeComponents = nodeComponents; } + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one public override bool Equals(object other) { try { - var unused = (DescantNodeData) other; + _ = (DescantNodeData) other; } catch { @@ -45,7 +78,12 @@ public override bool Equals(object other) return Equals((DescantNodeData)other); } -#if UNITY_EDITOR + #if UNITY_EDITOR + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantNodeData has the same data as this one protected bool Equals(DescantNodeData other) { return @@ -54,8 +92,11 @@ protected bool Equals(DescantNodeData other) Position == other.Position && DescantEditorUtilities.AreListsEqual(NodeComponents, other.NodeComponents); } -#endif + #endif + /// + /// Overridden ToString method + /// public override string ToString() { string temp = ""; @@ -73,25 +114,42 @@ public override string ToString() [Serializable] public class DescantChoiceNodeData : DescantNodeData { + /// + /// The list of possible choices that the player can make at the ChoiceNode + /// public List Choices = new List(); + /// + /// Parameterized constructor + /// + /// The custom name of the node + /// The unique identifier ID for the node + /// The type of this node + /// The node's current position + /// The list of Components attached to the node + /// The list of possible choices that the player can make at the ChoiceNode public DescantChoiceNodeData( string name, string type, int id, Vector2 position, List choices, - List nodeComponents) + List nodeComponents) : base(name, type, id, position, nodeComponents) { Choices = choices; } + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one public override bool Equals(object other) { try { - var unused = (DescantChoiceNodeData) other; + _ = (DescantChoiceNodeData) other; } catch { @@ -101,15 +159,23 @@ public override bool Equals(object other) return Equals((DescantChoiceNodeData)other); } -#if UNITY_EDITOR + #if UNITY_EDITOR + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantChoiceNodeData has the same data as this one public bool Equals(DescantChoiceNodeData other) { return base.Equals(other) && DescantEditorUtilities.AreListsEqual(Choices, other.Choices); } -#endif + #endif + /// + /// Overridden ToString method + /// public override string ToString() { string temp = ""; @@ -127,25 +193,42 @@ public override string ToString() [Serializable] public class DescantResponseNodeData : DescantNodeData { + /// + /// The response text at the ResponseNode + /// public string Response; + /// + /// Parameterized constructor + /// + /// The custom name of the node + /// The unique identifier ID for the node + /// The type of this node + /// The node's current position + /// The list of Components attached to the node + /// The response text at the ResponseNode public DescantResponseNodeData( string name, string type, int id, Vector2 position, string response, - List nodeComponents) + List nodeComponents) : base(name, type, id, position, nodeComponents) { Response = response; } + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one public override bool Equals(object other) { try { - var unused = (DescantResponseNodeData) other; + _ = (DescantResponseNodeData) other; } catch { @@ -155,13 +238,23 @@ public override bool Equals(object other) return Equals((DescantResponseNodeData)other); } + #if UNITY_EDITOR + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantResponseNodeData has the same data as this one public bool Equals(DescantResponseNodeData other) { return base.Equals(other) && Response == other.Response; } + #endif + /// + /// Overridden ToString method + /// public override string ToString() { return base.ToString() + " (" + Response + ")"; @@ -174,11 +267,18 @@ public override string ToString() [Serializable] public class DescantStartNodeData : DescantNodeData { + /// + /// Parameterized constructor + /// + /// The custom name of the node + /// The unique identifier ID for the node + /// The node's current position + /// The list of Components attached to the node public DescantStartNodeData( string name, string type, Vector2 position, - List nodeComponents) + List nodeComponents) : base(name, type, 0, position, nodeComponents) { } } @@ -188,12 +288,20 @@ public DescantStartNodeData( [Serializable] public class DescantEndNodeData : DescantNodeData { + /// + /// Parameterized constructor + /// + /// The custom name of the node + /// The unique identifier ID for the node + /// The type of this node + /// The node's current position + /// The list of Components attached to the node public DescantEndNodeData( string name, string type, int id, Vector2 position, - List nodeComponents) + List nodeComponents) : base(name, type, id, position, nodeComponents) { } } } \ No newline at end of file diff --git a/Editor/Data/DescantOtherData.cs b/Editor/Data/DescantOtherData.cs index 9a2cd13..af7b1a4 100644 --- a/Editor/Data/DescantOtherData.cs +++ b/Editor/Data/DescantOtherData.cs @@ -10,12 +10,39 @@ namespace DescantEditor [Serializable] public class DescantGroupData { + /// + /// The group's custom name + /// public string Name; + + /// + /// The group's ID + /// public int ID; + + /// + /// The group's position + /// public Vector2 Position; + + /// + /// The names of the nodes contained within the group + /// public List Nodes; + + /// + /// The IDs of the nodes contained within the group + /// public List NodeIDs; + /// + /// Parameterized constructor + /// + /// The group's custom name + /// The group's ID + /// The group's position + /// The names of the nodes contained within the group + /// The IDs of the nodes contained within the group public DescantGroupData(string name, int id, Vector2 position, List nodes, List nodeIDs) { Name = name; @@ -25,11 +52,16 @@ public DescantGroupData(string name, int id, Vector2 position, List node NodeIDs = nodeIDs; } + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one public override bool Equals(object other) { try { - var unused = (DescantGroupData) other; + _ = (DescantGroupData) other; } catch { @@ -39,7 +71,12 @@ public override bool Equals(object other) return Equals((DescantGroupData)other); } -#if UNITY_EDITOR + #if UNITY_EDITOR + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantGroupData has the same data as this one public bool Equals(DescantGroupData other) { return @@ -49,8 +86,11 @@ public bool Equals(DescantGroupData other) DescantEditorUtilities.AreListsEqual(Nodes, other.Nodes) && DescantEditorUtilities.AreListsEqual(NodeIDs, other.NodeIDs); } -#endif + #endif + /// + /// Overridden ToString method + /// public override string ToString() { string temp = ""; @@ -69,12 +109,41 @@ public override string ToString() [Serializable] public class DescantConnectionData { + /// + /// The name of the node the connection is coming from + /// public string From; + + /// + /// The ID of the node the connection is coming from + /// public int FromID; + + /// + /// The name of the node the connection is going to + /// public string To; + + /// + /// The ID of the node the connection is going to + /// public int ToID; - public int ChoiceIndex; // base 1 + + /// + /// The index of the port that this connection is coming from (base 1 for ChoiceNodes and ResponseNodes) + /// + public int ChoiceIndex; + /// + /// Parameterized constructor + /// + /// The name of the node the connection is coming from + /// The ID of the node the connection is coming from + /// The name of the node the connection is going to + /// The ID of the node the connection is going to + /// + /// The index of the port that this connection is coming from (base 1 for ChoiceNodes and ResponseNodes) + /// public DescantConnectionData(string from, int fromID, string to, int toID, int choiceIndex = 0) { From = from; @@ -83,12 +152,35 @@ public DescantConnectionData(string from, int fromID, string to, int toID, int c ToID = toID; ChoiceIndex = choiceIndex; } + + /// + /// Checks to make sure that the connection isn't an illegal one coming from a Choice node's input port + /// + /// Whether this connection is illegally coming from a Choice node's input port + public bool IllegalChoiceFrom() + { + return From.Trim() == "Choice" && ChoiceIndex == 0; + } + /// + /// Determines whether the connection points to itself + /// + /// + public bool ToItself() + { + return From == To && FromID == ToID; + } + + /// + /// Overridden Equals method + /// + /// The object being compared against + /// Whether the other object has the same data as this one public override bool Equals(object other) { try { - var unused = (DescantConnectionData) other; + _ = (DescantConnectionData) other; } catch { @@ -98,6 +190,12 @@ public override bool Equals(object other) return Equals((DescantConnectionData)other); } + #if UNITY_EDITOR + /// + /// Custom Equals method + /// + /// The data object being compared against + /// Whether the other DescantConnectionData has the same data as this one public bool Equals(DescantConnectionData other) { return @@ -105,25 +203,11 @@ public bool Equals(DescantConnectionData other) To == other.To && ToID == other.ToID && ChoiceIndex == other.ChoiceIndex; } + #endif /// - /// Checks to make sure that the connection isn't an illegal one coming from a Choice node's input port + /// Overridden ToString method /// - /// Whether this connection is illegally coming from a Choice node's input port - public bool IllegalChoiceFrom() - { - return From.Trim() == "Choice" && ChoiceIndex == 0; - } - - /// - /// Determines whether the connection points to itself - /// - /// - public bool ToItself() - { - return From == To && FromID == ToID; - } - public override string ToString() { return GetType() + " (" + FromID + From + " " + ToID + To + " " + ChoiceIndex + ")"; diff --git a/Editor/DescantEditorUtilities.cs b/Editor/DescantEditorUtilities.cs index 9146778..c97a521 100644 --- a/Editor/DescantEditorUtilities.cs +++ b/Editor/DescantEditorUtilities.cs @@ -202,10 +202,10 @@ public static bool AreListsEqual(List a, List b) /// The actor data to be saved public static void SaveActor(bool newFile, DescantActor data) { -#if UNITY_EDITOR + #if UNITY_EDITOR // Setting the local path if this is the first time if (newFile) data.Path = GetCurrentLocalDirectory() + data.Name + ".descactor.json"; -#endif + #endif DescantUtilities.RoundObjectToDecimal(data, 2); diff --git a/Editor/DescantNodeComponentVisualElement.cs b/Editor/DescantNodeComponentVisualElement.cs index ce2515f..97cdbc7 100644 --- a/Editor/DescantNodeComponentVisualElement.cs +++ b/Editor/DescantNodeComponentVisualElement.cs @@ -19,7 +19,7 @@ public class DescantNodeComponentVisualElement : VisualElement /// /// The Component that this visual element is representing /// - public DescantNodeComponent Component { get; } + public DescantComponent Component { get; } DescantGraphView graphView; // The DescantGraphView (used for saving) DescantNode node; // The node that this Component is attached to @@ -41,7 +41,7 @@ public DescantNodeComponentVisualElement( DescantGraphView graph, DescantNode descantNode, string name, - DescantNodeComponent component) + DescantComponent component) { graphView = graph; node = descantNode; @@ -50,10 +50,10 @@ public DescantNodeComponentVisualElement( // If the Component is null (i.e. it's being created for the first time), we create a new instance of it if (component == null) { - List types = DescantComponentUtilities.GetAllNodeComponentTypes(); - var temp = types[DescantComponentUtilities.TrimmedNodeComponentTypes(types).IndexOf(Name)]; + List types = DescantComponentUtilities.GetComponentTypes(); + var temp = types[DescantComponentUtilities.GetTrimmedComponentTypes(types).IndexOf(Name)]; - Component = (DescantNodeComponent) Activator.CreateInstance(temp); + Component = (DescantComponent) Activator.CreateInstance(temp); } else Component = component; // Otherwise we just use the previously saved copy } @@ -364,10 +364,10 @@ void ToggleCollapseComponent() /// void RemoveComponent() { - node.Components[Name]--; // Decrementing the Component's node's count for this particular type of Component + node.ComponentCounts[Name]--; // Decrementing the Component's node's count for this particular type of Component // Now that we've removed it from the count, can future nodes of this type be added? - if (node.Components[Name] < DescantComponentUtilities.GetNodeComponentMaximum(Name)) + if (node.ComponentCounts[Name] < DescantComponentUtilities.GetComponentMaximum(Name)) { node.ComponentDropdown.choices.Add(Name); node.ComponentDropdown.choices.Sort(); diff --git a/Editor/Nodes/DescantChoiceNode.cs b/Editor/Nodes/DescantChoiceNode.cs index c810a1e..81dde63 100644 --- a/Editor/Nodes/DescantChoiceNode.cs +++ b/Editor/Nodes/DescantChoiceNode.cs @@ -11,6 +11,11 @@ namespace DescantEditor /// public class DescantChoiceNode : DescantNode { + /// + /// Parameterized constructor + /// + /// The GraphView for this editor window + /// The position to spawn the node at public DescantChoiceNode( DescantGraphView graphView, Vector2 position) diff --git a/Editor/Nodes/DescantEndNode.cs b/Editor/Nodes/DescantEndNode.cs index 0671688..8049b21 100644 --- a/Editor/Nodes/DescantEndNode.cs +++ b/Editor/Nodes/DescantEndNode.cs @@ -11,6 +11,11 @@ namespace DescantEditor /// public class DescantEndNode : DescantNode { + /// + /// Parameterized constructor + /// + /// The GraphView for this editor window + /// The position to spawn the node at public DescantEndNode( DescantGraphView graphView, Vector2 position) diff --git a/Editor/Nodes/DescantNode.cs b/Editor/Nodes/DescantNode.cs index 26fcd55..492dce5 100644 --- a/Editor/Nodes/DescantNode.cs +++ b/Editor/Nodes/DescantNode.cs @@ -15,20 +15,29 @@ namespace DescantEditor public abstract class DescantNode : Node { /// - /// The custom name of this node, - /// which is independent from its type or ID + /// The custom name of this node /// public string Name { get; set; } /// - /// The unique identifier for this node, + /// The unique identifier ID for this node, /// used to differentiate it from others of the name type and/or name /// public int ID { get; set; } + /// + /// The type of this node + /// public DescantNodeType Type { get; protected set; } - public Dictionary Components { get; } + /// + /// The number of components of each type that are attached to this node + /// + public Dictionary ComponentCounts { get; } + + /// + /// The dropdown VisualElement for this node + /// public PopupField ComponentDropdown { get; private set; } /// @@ -36,11 +45,14 @@ public abstract class DescantNode : Node /// protected DescantGraphView GraphView; - protected DescantNode( - DescantGraphView graphView, - Vector2 position) + /// + /// Parameterized constructor + /// + /// The GraphView for this editor window + /// The position to spawn the node at + protected DescantNode(DescantGraphView graphView, Vector2 position) { - Components = new Dictionary(); + ComponentCounts = new Dictionary(); GraphView = graphView; SetPosition(new Rect(position, Vector2.zero)); @@ -98,9 +110,9 @@ protected void Draw() })); } - List nodeComponents = DescantComponentUtilities.GetAllNodeComponentTypes(); - - List nodeComponentNames = DescantComponentUtilities.TrimmedNodeComponentTypes(nodeComponents + // Getting a formatted list of all the types of Components that can be attached to this node + List nodeComponentNames = DescantComponentUtilities.GetTrimmedComponentTypes( + DescantComponentUtilities.GetComponentTypes() .Where(type => { var tempType = (((NodeTypeAttribute) type.GetCustomAttributes( @@ -112,11 +124,13 @@ protected void Draw() }) .ToList()); + // Initializing the dropdown with the appropriate options from above ComponentDropdown = new PopupField(nodeComponentNames, 0); ComponentDropdown.AddToClassList("node_component_dropdown"); ComponentDropdown.value = "Add Component"; extensionContainer.Add(ComponentDropdown); + // When the dropdown value is changed, we create a new Component and reset the dropdown ComponentDropdown.RegisterValueChangedCallback(callback => { string componentName = callback.newValue; @@ -137,15 +151,26 @@ public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) { evt.menu.AppendAction("Delete", actionEvent => { RemoveNode(); }); } - - public void AddComponent(string componentName, DescantNodeComponent component) + + /// + /// Creates and adds a new DescantNodeComponentVisualElement to this node + /// + /// The name of the Component type to add + /// + /// The DescantNodeComponent object that the VisualElement will be representing + /// (if null, the DescantNodeComponentVisualElement will create a new instance of it) + /// + public void AddComponent(string componentName, DescantComponent component) { - if (!Components.ContainsKey(componentName)) Components.Add(componentName, 1); - else Components[componentName]++; - - if (Components[componentName] >= DescantComponentUtilities.GetNodeComponentMaximum(componentName)) + // Updating the count for this Component type + if (!ComponentCounts.ContainsKey(componentName)) ComponentCounts.Add(componentName, 1); + else ComponentCounts[componentName]++; + + // If we've hit the maximum, we remove the type from the list + if (ComponentCounts[componentName] >= DescantComponentUtilities.GetComponentMaximum(componentName)) ComponentDropdown.choices.RemoveAt(ComponentDropdown.choices.IndexOf(componentName)); - + + // Creating a new VisualElement DescantNodeComponentVisualElement temp = new DescantNodeComponentVisualElement( GraphView, this, diff --git a/Editor/Nodes/DescantNodeGroup.cs b/Editor/Nodes/DescantNodeGroup.cs index a282e10..0770a00 100644 --- a/Editor/Nodes/DescantNodeGroup.cs +++ b/Editor/Nodes/DescantNodeGroup.cs @@ -28,6 +28,11 @@ public class DescantNodeGroup : Group /// DescantGraphView GraphView; + /// + /// Parameterized constructor + /// + /// The GraphView for this editor window + /// The position to spawn the group at public DescantNodeGroup( DescantGraphView graphView, Vector2 position) diff --git a/Editor/Nodes/DescantResponseNode.cs b/Editor/Nodes/DescantResponseNode.cs index 7db7bcc..65dd0e7 100644 --- a/Editor/Nodes/DescantResponseNode.cs +++ b/Editor/Nodes/DescantResponseNode.cs @@ -11,6 +11,11 @@ namespace DescantEditor /// public class DescantResponseNode : DescantNode { + /// + /// Parameterized constructor + /// + /// The GraphView for this editor window + /// The position to spawn the node at public DescantResponseNode( DescantGraphView graphView, Vector2 position) diff --git a/Editor/Nodes/DescantStartNode.cs b/Editor/Nodes/DescantStartNode.cs index 287e228..a846664 100644 --- a/Editor/Nodes/DescantStartNode.cs +++ b/Editor/Nodes/DescantStartNode.cs @@ -11,6 +11,11 @@ namespace DescantEditor /// public class DescantStartNode : DescantNode { + /// + /// Parameterized constructor + /// + /// The GraphView for this editor window + /// The position to spawn the node at public DescantStartNode( DescantGraphView graphView, Vector2 position) diff --git a/Editor/Window/DescantActorEditor.cs b/Editor/Window/DescantActorEditor.cs index 00f98a7..108b820 100644 --- a/Editor/Window/DescantActorEditor.cs +++ b/Editor/Window/DescantActorEditor.cs @@ -12,29 +12,35 @@ namespace DescantEditor { public class DescantActorEditor : EditorWindow { - VisualElement UI; - Toolbar toolbar; - VisualElement actor; - - VisualElement statistics; - VisualElement topics; - VisualElement relationships; - TextField dialogueAttempts; + VisualElement UI; // The root UI element for the whole editor + Toolbar toolbar; // The toolbar at the top of teh editor + VisualElement actor; // The root element for all the actor VisualElements + + VisualElement statistics; // The parent of the statistics dictionary + VisualElement topics; // The parent of the topics list + VisualElement relationships; // The parent of the relationships dictionary + TextField dialogueAttempts; // The dialogue attempts field - DescantActor data; - - bool loaded; - string lastLoaded; + DescantActor data; // The actor currently being displayed + + // The full disc path of the last loaded Descant actor + // (so that it can be re-loaded when the editor is re-loaded (e.g. when there is a script change)) + string lastPath; + bool GUICreated; // Whether a Descant actor is currently loaded into the editor [MenuItem("Window/Descant/Descant Actor Editor"), MenuItem("Tools/Descant/Descant Actor Editor")] public static void Open() { GetWindow("Descant Actor Editor"); } + + #region GUI void CreateGUI() { - if (loaded) + // If the actor data has already been loaded into the editor, we simple generate the actor UI and toolbar + // (they're dependant on the data having been previously loaded) + if (GUICreated) { UI = new VisualElement(); UI.AddToClassList("ui"); @@ -46,67 +52,95 @@ void CreateGUI() AddStyleSheet(); } + // Otherwise, we first load the data before adding the actor UI view and toolbar + // (the Load method will call CreateGUI again when it has finished) else { - Load(lastLoaded); + Load(lastPath); AssetDatabase.Refresh(); } - loaded = false; + // Resetting the loaded variable to indicate that the UI should be + // reloaded if CreateGUI is ever called again when Unity is refreshed + // (otherwise the actor UI and toolbar would be added without any data to initialize them with) + GUICreated = false; } + /// + /// Removes the actor UI and toolbar from the hierarchy + /// void RemoveGUI() { DescantEditorUtilities.RemoveElement(UI); } + /// + /// Reloads the GUI (presumably after the DescantActorData object has been changed) + /// void ReloadGUI() { RemoveGUI(); CreateGUI(); } + /// + /// Adds the stylesheet to the editor + /// (the DescantGraphView needs to also have the style sheet set) + /// void AddStyleSheet() { StyleSheet styleSheet = (StyleSheet)EditorGUIUtility.Load("Packages/Descant/Assets/DescantActorEditorStyleSheet.uss"); rootVisualElement.styleSheets.Add(styleSheet); } + /// + /// Initializes the toolbar's VisualElements + /// void AddToolbar() { toolbar = new Toolbar(); UI.Add(toolbar); - + + // Initializing the title section VisualElement toolbarTitle = new VisualElement(); toolbarTitle.AddToClassList("toolbar-title"); toolbar.Add(toolbarTitle); + // Initializing the Descant actor's file name TextElement fileName = new TextElement(); fileName.text = data.Name; fileName.AddToClassList("toolbar-filename"); toolbarTitle.Add(fileName); - + + // Initializing the save section VisualElement saveSection = new VisualElement(); saveSection.AddToClassList("save-section"); toolbar.Add(saveSection); + // Initializing the save button Button save = new Button(); - save.clicked += ReadAndSave; + save.clicked += GetAndSave; save.text = "Save"; saveSection.Add(save); + // Initializing the close button Button close = new Button(); close.clicked += Unload; close.text = "Close"; saveSection.Add(close); } + /// + /// Initializes the DescantActor UI + /// void AddActor() { actor = new VisualElement(); actor.AddToClassList("actor"); UI.Add(actor); + // Initializing the sections + statistics = AddActorDictionary(data.StatisticKeys, data.StatisticValues, "Statistics"); topics = AddActorList(data.Topics, "Topics"); relationships = AddActorDictionary(data.RelationshipKeys, data.RelationshipValues, "Relationships"); @@ -122,18 +156,63 @@ void AddActor() dialogueAttempts.value = DescantUtilities.FilterText(callback.newValue); }); } + + #endregion + + #region Actor Lists + + /// + /// Creates a new GUI section for the actor that represents a list of items + /// + /// The actual list that will be represented + /// The name of the list + /// A new VisualElement list of the items + VisualElement AddActorList(List lst, string name) + { + // Initializing the list parent + VisualElement list = new VisualElement(); + list.AddToClassList("actor_list"); + actor.Add(list); + + // Initializing the list name + TextElement listName = new TextElement(); + listName.text = name; + listName.AddToClassList("list_name"); + list.Add(listName); + + // Initializing the button to add new items + Button add = new Button(); + add.text = "Add new " + name.ToLower().Substring(0, name.Length - 1); + add.clicked += () => AddListItem(list, ""); + add.AddToClassList("add_button"); + list.Add(add); + + // Adding all the items in + foreach (var i in lst) + AddListItem(list, i); + + return list; + } + /// + /// Generates a single list item (for use with AddActorList) + /// + /// The parent list that this element will be inserted into + /// The value to insert into the item void AddListItem(VisualElement list, T v) { + // Initializing the item parent VisualElement item = new VisualElement(); item.AddToClassList("dictionary_item"); list.Insert(list.childCount - 1, item); + // Initializing the item remove button Button remove = new Button(); remove.text = "X"; remove.clicked += () => DescantEditorUtilities.RemoveElement(item); item.Add(remove); - + + // Initializing the item value field TextField value = new TextField(); value.value = v.ToString(); item.Add(value); @@ -143,35 +222,56 @@ void AddListItem(VisualElement list, T v) value.value = DescantUtilities.FilterText(callback.newValue); }); } - - VisualElement AddActorList(List lst, string name) + + #endregion + + #region Actor Dictionaries + + /// + /// Creates a new GUI section for the actor that represents a dictionary + /// + /// + /// + /// The name of the dictionary + /// A new VisualElement dictionary + VisualElement AddActorDictionary(List keys, List values, string name) { - VisualElement list = new VisualElement(); - list.AddToClassList("actor_list"); - actor.Add(list); - - TextElement listName = new TextElement(); - listName.text = name; - listName.AddToClassList("list_name"); - list.Add(listName); + // Initializing the dictionary parent + VisualElement dictionary = new VisualElement(); + dictionary.AddToClassList("actor_list"); + actor.Add(dictionary); + + // Initializing the dictionary name + TextElement dictionaryName = new TextElement(); + dictionaryName.text = name; + dictionaryName.AddToClassList("list_name"); + dictionary.Add(dictionaryName); + // Initializing the button to add new entries Button add = new Button(); add.text = "Add new " + name.ToLower().Substring(0, name.Length - 1); - add.clicked += () => AddListItem(list, ""); + add.clicked += () => AddDictionaryItem(dictionary, "", 0); add.AddToClassList("add_button"); - list.Add(add); + dictionary.Add(add); - foreach (var i in lst) - AddListItem(list, i); + // Adding all the entries in + for (int i = 0; i < keys.Count; i++) + AddDictionaryItem(dictionary, keys[i], values[i]); - return list; + return dictionary; } - void AddDictionaryItem(VisualElement list, T k, U v) + /// + /// Generates a single dictionary entry (for use with AddActorDictionary) + /// + /// The parent dictionary that this element will be inserted into + /// The key to insert into the entry + /// The value to insert into the entry + void AddDictionaryItem(VisualElement dictionary, T k, U v) { VisualElement item = new VisualElement(); item.AddToClassList("dictionary_item"); - list.Insert(list.childCount - 1, item); + dictionary.Insert(dictionary.childCount - 1, item); Button remove = new Button(); remove.text = "X"; @@ -197,58 +297,23 @@ void AddDictionaryItem(VisualElement list, T k, U v) }); } - VisualElement AddActorDictionary(List keys, List values, string name) - { - VisualElement list = new VisualElement(); - list.AddToClassList("actor_list"); - actor.Add(list); - - TextElement listName = new TextElement(); - listName.text = name; - listName.AddToClassList("list_name"); - list.Add(listName); - - Button add = new Button(); - add.text = "Add new " + name.ToLower().Substring(0, name.Length - 1); - add.clicked += () => AddDictionaryItem(list, "", 0); - add.AddToClassList("add_button"); - list.Add(add); - - for (int i = 0; i < keys.Count; i++) - AddDictionaryItem(list, keys[i], values[i]); - - return list; - } - - public void Load(string fullPath) - { - // Making sure the path isn't null or empty - if (fullPath != null && fullPath.Trim() != "") - { - lastLoaded = fullPath; - - data = DescantEditorUtilities.LoadActorFromPath(fullPath); - - // Reloading the name and path, in case they got changed after the last time this file was loaded - data.Name = DescantUtilities.FilterText(DescantEditorUtilities.GetDescantFileNameFromPath(fullPath, false)); - data.Path = DescantEditorUtilities.RemoveBeforeLocalPath(fullPath); - - DescantEditorUtilities.SaveActor(false, data); - - loaded = true; - - // Removing the old GUI (if it exists) and - // creating the new GUI (now that the data has been loaded) - ReloadGUI(); - } - } - - void ReadAndSave() + #endregion + + #region Saving And Loading + + /// + /// Checks through the entire actor UI for relevant information and saves it to the file + /// + void GetAndSave() { - var statisticsChildren = statistics.Children().ToList(); + // Resetting the actor's statistics lists data.StatisticKeys = new List(); data.StatisticValues = new List(); + + // Getting the statistics dictionary entries + var statisticsChildren = statistics.Children().ToList(); + // Getting the values from the children and adding them to the lists for (int i = 1; i < statisticsChildren.Count - 1; i++) { var temp = statisticsChildren[i].Children().ToList(); @@ -257,16 +322,24 @@ void ReadAndSave() data.StatisticValues.Add(float.Parse(((TextField)temp[2]).value)); } - var topicsChildren = topics.Children().ToList(); + // Resetting the actor's topics list data.Topics = new List(); + + // Getting the topics list items + var topicsChildren = topics.Children().ToList(); + // Getting the values from the children and adding them to the list for (int i = 1; i < topicsChildren.Count - 1; i++) data.Topics.Add(((TextField)topicsChildren[i].Children().ToList()[1]).value); - var relationshipsChildren = relationships.Children().ToList(); + // Resetting the actor's relationships lists data.RelationshipKeys = new List(); data.RelationshipValues = new List(); + + // Getting the relationships dictionary entries + var relationshipsChildren = relationships.Children().ToList(); + // Getting the values from the children and adding them to the lists for (int i = 1; i < relationshipsChildren.Count - 1; i++) { var temp = relationshipsChildren[i].Children().ToList(); @@ -274,32 +347,71 @@ void ReadAndSave() data.RelationshipKeys.Add(((TextField)temp[1]).value); data.RelationshipValues.Add(float.Parse(((TextField)temp[2]).value)); } - + + // Getting the values from the dialogue attempts field and applying it to the value data.DialogueAttempts = int.Parse(dialogueAttempts.value); + // (the actual saving method must be in a separate, non-Editor class + // so that both Editor and non-Editor classes can access it) DescantEditorUtilities.SaveActor(false, data); + AssetDatabase.Refresh(); } + /// + /// Loads the data from a Descant actor file + /// + /// The full disc path to the Descant file to load + public void Load(string fullPath) + { + // Making sure the path isn't null or empty + if (fullPath != null && fullPath.Trim() != "") + { + lastPath = fullPath; + + data = DescantEditorUtilities.LoadActorFromPath(fullPath); + + // Reloading the name and path, in case they got changed after the last time this file was loaded + data.Name = DescantUtilities.FilterText(DescantEditorUtilities.GetDescantFileNameFromPath(fullPath, false)); + data.Path = DescantEditorUtilities.RemoveBeforeLocalPath(fullPath); + + DescantEditorUtilities.SaveActor(false, data); + + GUICreated = true; + + // Removing the old GUI (if it exists) and + // creating the new GUI (now that the data has been loaded) + ReloadGUI(); + } + } + + /// + /// Un-loads the current data and GUI + /// void Unload() { data = null; - loaded = false; - lastLoaded = null; + GUICreated = false; + lastPath = null; RemoveGUI(); } + /// + /// Creates a new blank file, and reloads the GUI + /// public void NewFile() { data = new DescantActor("New_Descant_Actor"); DescantEditorUtilities.SaveActor(true, data); - loaded = true; + GUICreated = true; ReloadGUI(); } + + #endregion } } #endif \ No newline at end of file diff --git a/Editor/Window/DescantEditor.cs b/Editor/Window/DescantEditor.cs index 78373dc..31172c2 100644 --- a/Editor/Window/DescantEditor.cs +++ b/Editor/Window/DescantEditor.cs @@ -18,42 +18,19 @@ public class DescantEditor : EditorWindow /// public DescantGraphData data; - /// - /// The graph view part the editor - /// - DescantGraphView graphView; - - /// - /// The toolbar part of the editor - /// - Toolbar toolbar; - - Toggle typewriter; - - TextField typewriterSpeed; - - /// - /// The autosave toggle button in the toolbar - /// - Toggle autoSave; + DescantGraphView graphView; // The graph view part the editor + Toolbar toolbar; // The toolbar part of the editor - /// - /// The unsaved changes marker in the toolbar - /// - TextElement unsaved; - - /// - /// Whether a Descant graph is currently loaded into the editor - /// - bool loaded; + Toggle typewriter; // The Toggle VisualElement for turning the typewriter on and off + TextField typewriterSpeed; // The field for inputting the typewriter speed - /// - /// The full disc path of the last loaded Descant graph - /// (so that it can be re-loaded when the editor is re-loaded (e.g. when there is a script change)) - /// - string lastLoaded; + Toggle autoSave; // The autosave toggle button in the toolbar + TextElement unsaved; // The unsaved changes marker in the toolbar - // TODO: ctrl-S functionality + // The full disc path of the last loaded Descant graph + // (so that it can be re-loaded when the editor is re-loaded (e.g. when there is a script change)) + string lastPath; + bool GUICreated; // Whether a Descant graph is currently loaded into the editor [MenuItem("Window/Descant/Descant Graph Editor"), MenuItem("Tools/Descant/Descant Graph Editor")] public static void Open() @@ -61,11 +38,13 @@ public static void Open() GetWindow("Descant Graph Editor"); } + #region GUI + void CreateGUI() { // If the graph data has already been loaded into the editor, we simple generate the graph view and toolbar // (they're dependant on the data having been previously loaded) - if (loaded) + if (GUICreated) { AddGraphView(); AddToolbar(); @@ -76,14 +55,14 @@ void CreateGUI() // (the Load method will call CreateGUI again when it has finished) else { - Load(lastLoaded); + Load(lastPath); AssetDatabase.Refresh(); } // Resetting the loaded variable to indicate that the UI should be - // reloaded if CreateGUI is ever called again naturally + // reloaded if CreateGUI is ever called again when Unity is refreshed // (otherwise the graph view and toolbar would be added without any data to initialize them with) - loaded = false; + GUICreated = false; } /// @@ -115,6 +94,16 @@ void AddGraphView() rootVisualElement.Add(graphView); graphView.StretchToParentSize(); // Making sure it's properly scaled up } + + /// + /// Adds the stylesheet to the editor + /// (the DescantGraphView needs to also have the style sheet set) + /// + void AddStyleSheet() + { + StyleSheet styleSheet = (StyleSheet)EditorGUIUtility.Load("Packages/Descant/Assets/DescantGraphEditorStyleSheet.uss"); + rootVisualElement.styleSheets.Add(styleSheet); + } /// /// Initializes the toolbar's VisualElements @@ -147,16 +136,19 @@ void AddToolbar() saveSection.AddToClassList("save-section"); toolbar.Add(saveSection); + // Initializing the typewriter toggle typewriter = new Toggle("Typewriter:"); typewriter.value = data.Typewriter; saveSection.Add(typewriter); + // Initializing the typewriter speed typewriterSpeed = new TextField("Speed:"); typewriterSpeed.value = data.TypewriterSpeed.ToString(); saveSection.Add(typewriterSpeed); if (!typewriter.value) typewriterSpeed.visible = false; + // Adding a callback for when the typewriter toggle value is changed typewriter.RegisterValueChangedCallback(callback => { typewriterSpeed.visible = typewriter.value; @@ -196,16 +188,10 @@ void AddToolbar() close.text = "Close"; saveSection.Add(close); } + + #endregion - /// - /// Adds the stylesheet to the editor - /// (the DescantGraphView needs to also have the style sheet set) - /// - void AddStyleSheet() - { - StyleSheet styleSheet = (StyleSheet)EditorGUIUtility.Load("Packages/Descant/Assets/DescantGraphEditorStyleSheet.uss"); - rootVisualElement.styleSheets.Add(styleSheet); - } + #region Saving and Loading /// /// Checks through the entire graph view and toolbar for relevant information, @@ -474,7 +460,7 @@ void Save(bool refresh = false) } /// - /// Loads the data from a Descant file + /// Loads the data from a Descant graph file /// /// The full disc path to the Descant file to load public void Load(string fullPath) @@ -482,7 +468,7 @@ public void Load(string fullPath) // Making sure the path isn't null or empty if (fullPath != null && fullPath.Trim() != "") { - lastLoaded = fullPath; + lastPath = fullPath; data = DescantGraphData.LoadGraphFromPath(fullPath); @@ -492,7 +478,7 @@ public void Load(string fullPath) data.Save(false); - loaded = true; + GUICreated = true; // Removing the old GUI (if it exists) and // creating the new GUI (now that the data has been loaded) @@ -507,8 +493,8 @@ void Unload() { data = null; - loaded = false; - lastLoaded = null; + GUICreated = false; + lastPath = null; RemoveGUI(); } @@ -521,10 +507,12 @@ public void NewFile() data = new DescantGraphData("New_Descant_Graph"); data.Save(true); - loaded = true; + GUICreated = true; ReloadGUI(); } + + #endregion } } #endif \ No newline at end of file diff --git a/Editor/Window/DescantGraphView.cs b/Editor/Window/DescantGraphView.cs index f83c980..efa573d 100644 --- a/Editor/Window/DescantGraphView.cs +++ b/Editor/Window/DescantGraphView.cs @@ -72,6 +72,12 @@ public class DescantGraphView : GraphView IManipulator startNodeManipulator; // The 'Add Start Node' contextual menu manipulator List contextMenuManipulators = new List(); // The list of contextual menu manipulators for nodes + #region Constructor + + /// + /// Parameterized constructor + /// + /// The editor window that this graph view is a part of public DescantGraphView(DescantEditor editor) { Editor = editor; @@ -104,7 +110,7 @@ public DescantGraphView(DescantEditor editor) foreach (var ij in i.NodeComponents) temp.AddComponent( - DescantComponentUtilities.GetTrimmedNodeComponentType(ij.GetType()), ij); + DescantComponentUtilities.GetTrimmedTypeName(ij.GetType()), ij); AddElement(temp); } @@ -117,7 +123,7 @@ public DescantGraphView(DescantEditor editor) foreach (var ji in j.NodeComponents) temp.AddComponent( - DescantComponentUtilities.GetTrimmedNodeComponentType(ji.GetType()), ji); + DescantComponentUtilities.GetTrimmedTypeName(ji.GetType()), ji); AddElement(temp); } @@ -133,7 +139,7 @@ public DescantGraphView(DescantEditor editor) foreach (var k in data.StartNode.NodeComponents) temp.AddComponent( - DescantComponentUtilities.GetTrimmedNodeComponentType(k.GetType()), k); + DescantComponentUtilities.GetTrimmedTypeName(k.GetType()), k); AddElement(temp); } @@ -148,7 +154,7 @@ public DescantGraphView(DescantEditor editor) foreach (var li in l.NodeComponents) temp.AddComponent( - DescantComponentUtilities.GetTrimmedNodeComponentType(li.GetType()), li); + DescantComponentUtilities.GetTrimmedTypeName(li.GetType()), li); AddElement(temp); } @@ -188,28 +194,8 @@ public DescantGraphView(DescantEditor editor) } } } - - /// - /// Overridden method to make sure that connections can only be made between DescantNodes that are: - /// a) Not of the same type and - /// b) Not in the same direction - /// - public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) - { - List compatiblePorts = new List(); - - ports.ForEach(port => - { - if (startPort == port) return; - if (startPort.node == port.node) return; - if (startPort.direction == port.direction) return; - if (startPort.name == port.name && startPort.name != "Response") return; - - compatiblePorts.Add(port); - }); - - return compatiblePorts; - } + + #endregion /// /// Initializes the grid background for the Descant graph @@ -221,20 +207,32 @@ void AddGridBackground() Insert(0, gridBackground); } - + /// - /// Removes all the node and group context menu manipulators + /// Adds all the GraphView manipulators (e.g. zooming, selection, etc.) + /// as well as the node and group context manu manipulators /// - public void RemoveContextMenuManipulators() + void AddManipulators() { - foreach (var i in contextMenuManipulators) - this.RemoveManipulator(i); + this.AddManipulator(new ContentDragger()); + this.AddManipulator(new ContentZoomer()); + this.AddManipulator(new SelectionDragger()); + this.AddManipulator(new RectangleSelector()); - contextMenuManipulators.Clear(); - - startNodeManipulator = null; + AddContextMenuManipulators(); } - + + /// + /// Initializes the stylesheet for this GraphView + /// + void AddStyleSheet() + { + StyleSheet styleSheet = (StyleSheet)EditorGUIUtility.Load("Packages/Descant/Assets/DescantGraphEditorStyleSheet.uss"); + styleSheets.Add(styleSheet); + } + + # region Contextual Menus + /// /// Adds all the node and group context menu manipulators /// @@ -249,17 +247,16 @@ public void AddContextMenuManipulators() } /// - /// Adds all the GraphView manipulators (e.g. zooming, selection, etc.) - /// as well as the node and group context manu manipulators + /// Removes all the node and group context menu manipulators /// - void AddManipulators() + public void RemoveContextMenuManipulators() { - this.AddManipulator(new ContentDragger()); - this.AddManipulator(new ContentZoomer()); - this.AddManipulator(new SelectionDragger()); - this.AddManipulator(new RectangleSelector()); + foreach (var i in contextMenuManipulators) + this.RemoveManipulator(i); - AddContextMenuManipulators(); + contextMenuManipulators.Clear(); + + startNodeManipulator = null; } /// @@ -332,6 +329,10 @@ IManipulator CreateNodeGroupContextualMenu() return context; } + + #endregion + + #region Node/Group creation /// /// Creates a new DescantChoiceNode @@ -452,15 +453,10 @@ DescantNodeGroup CreateNodeGroup(Vector2 groupPosition, string groupName = "", i return group; } - - /// - /// Initializes the stylesheet for this GraphView - /// - void AddStyleSheet() - { - StyleSheet styleSheet = (StyleSheet)EditorGUIUtility.Load("Packages/Descant/Assets/DescantGraphEditorStyleSheet.uss"); - styleSheets.Add(styleSheet); - } + + #endregion + + #region Ports /// /// Disconnects all the ports for some DescantNode container @@ -474,6 +470,32 @@ public void DisconnectPorts(VisualElement container, Port onlyThisPort = null) if (i.connected && (onlyThisPort == null || i.Equals(onlyThisPort))) DeleteElements(i.connections); } + + /// + /// Overridden method to make sure that connections can only be made between DescantNodes that are: + /// a) Not of the same type and + /// b) Not in the same direction + /// + public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) + { + List compatiblePorts = new List(); + + ports.ForEach(port => + { + if (startPort == port) return; + if (startPort.node == port.node) return; + if (startPort.direction == port.direction) return; + if (startPort.name == port.name && startPort.name != "Response") return; + + compatiblePorts.Add(port); + }); + + return compatiblePorts; + } + + #endregion + + #region Nodes /// /// Searches through all the DescantNodes in the graph and finds a matching one @@ -511,6 +533,8 @@ bool NodeMatches(DescantNode node, string nodeType, int nodeID) { return node.Type.ToString() == nodeType && node.ID == nodeID; } + + #endregion } } #endif \ No newline at end of file diff --git a/README.md b/README.md index e66bb27..0d62e9e 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ 1. `ChoiceNode`s represent player choices at certain moments within the dialogue, and `ResponseNode`s represent the NPC’s responses or statements. 1. If you want to have a `DescantActor`’s statistic show up within a `ChoiceNode` or `ResponseNode`'s text, write `{actor_name:statistic_name}`, and **Descant** will inject the statistic right into it. *(see the below for more info on `DescantActor`s)*. 1. The `StartNode` represents the place where a given dialogue begins, and `EndNode`s represent where it can end. - 1. More complex functionality can be added to nodes by adding `Components` (see the [Descant documentation](https://omch.tech/descant) for more info on each default component, as well as how to write your own). + 1. More complex functionality can be added to nodes by adding `Components` (see the [Component documentation](https://omch.tech/descant) for more info on each default component, as well as how to write your own). - **Descant Actors** 1. The **Descant Actor Editor** can be opened with `Tools/Descant/Descant Actor Editor` or by creating/editing a **Descant Actor** file. 2. New **Statistics**, **Topics**, and **Relationships** can be added with their respective **Add** buttons. @@ -68,7 +68,7 @@ ## Documentation - This `README` -- [Descant documentation](https://omch.tech/descant) +- [Component documentation](https://omch.tech/descant) - Planning - [Initial research](Documentation/interaction_research.md), [market survey](Documentation/system_review.xlsx), and [key pitfalls and successes](Documentation/pitfalls_and_sucesses.md) - [Features list](Documentation/features.md) diff --git a/package-lock.json b/package-lock.json index 2e8ebe7..7d0fb6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "descant", + "name": "com.owmacohe.descant", "version": "1.0.0", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index 66e7a22..ece6a73 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,24 @@ { - "name": "descant", + "name": "com.owmacohe.descant", "displayName": "Descant", "version": "1.0.0", + "description": "An enhanced and and user-friendly Unity dialogue system plugin.\n\nDescant aims to hit the sweet spot between quality UI, powerful features, and easy-to-lean functionality, while also addressing many of the game-specific consequences of the standard dialogue manager setup.\n\nPlease view the README before beginning development.", "unity": "2022.3", "unityRelease": "7f1", + "documentationUrl": "https://omch.tech/descant", "dependencies": { "com.unity.textmeshpro": "0.0.1-security" }, - "keywords": [], + "keywords": [ + "dialogue system", + "dialogue manager", + "dialogue", + "open-source", + "modular" + ], "author": { "name": "Owen Hellum", "email": "omch@protonmail.com", "url": "https://omch.tech" - }, - "description": "Descant is a Unity dialogue system plugin that aims to hit the sweet spot between quality UI, powerful features, and easy-to-lean functionality, while also addressing many of the game-specific consequences of the standard dialogue manager setup." + } }