Repository: TeodorVecerdi/DialogueGraph Branch: main Commit: 9837f4c05998 Files: 279 Total size: 457.3 KB Directory structure: gitextract_spodhmoi/ ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── Dependencies/ │ ├── SerializableCallback/ │ │ ├── .gitignore │ │ ├── Editor/ │ │ │ ├── SerializableCallbackDrawer.cs │ │ │ ├── SerializableCallbackDrawer.cs.meta │ │ │ ├── Siccity.SerializableCallback.Editor.asmdef │ │ │ └── Siccity.SerializableCallback.Editor.asmdef.meta │ │ ├── Editor.meta │ │ ├── LICENSE.md │ │ ├── LICENSE.md.meta │ │ ├── README.md │ │ ├── README.md.meta │ │ ├── Runtime/ │ │ │ ├── Attributes/ │ │ │ │ ├── TargetConstraintAttribute.cs │ │ │ │ └── TargetConstraintAttribute.cs.meta │ │ │ ├── Attributes.meta │ │ │ ├── InvokableCallback.cs │ │ │ ├── InvokableCallback.cs.meta │ │ │ ├── InvokableCallbackBase.cs │ │ │ ├── InvokableCallbackBase.cs.meta │ │ │ ├── InvokableEvent.cs │ │ │ ├── InvokableEvent.cs.meta │ │ │ ├── InvokableEventBase.cs │ │ │ ├── InvokableEventBase.cs.meta │ │ │ ├── SerializableCallback.cs │ │ │ ├── SerializableCallback.cs.meta │ │ │ ├── SerializableCallbackBase.cs │ │ │ ├── SerializableCallbackBase.cs.meta │ │ │ ├── SerializableEvent.cs │ │ │ ├── SerializableEvent.cs.meta │ │ │ ├── SerializableEventBase.cs │ │ │ ├── SerializableEventBase.cs.meta │ │ │ ├── Siccity.SerializableCallback.asmdef │ │ │ ├── Siccity.SerializableCallback.asmdef.meta │ │ │ ├── Test.cs │ │ │ └── Test.cs.meta │ │ ├── Runtime.meta │ │ ├── package.json │ │ └── package.json.meta │ ├── SerializableCallback.meta │ ├── SerializableDictionary/ │ │ ├── Editor/ │ │ │ ├── SerializableDictionary.Editor.asmdef │ │ │ ├── SerializableDictionary.Editor.asmdef.meta │ │ │ ├── SerializableDictionaryPropertyDrawer.cs │ │ │ └── SerializableDictionaryPropertyDrawer.cs.meta │ │ ├── Editor.meta │ │ ├── LICENSE.md │ │ ├── LICENSE.md.meta │ │ ├── Runtime/ │ │ │ ├── SerializableDictionary.Runtime.asmdef │ │ │ ├── SerializableDictionary.Runtime.asmdef.meta │ │ │ ├── SerializableDictionary.cs │ │ │ └── SerializableDictionary.cs.meta │ │ └── Runtime.meta │ └── SerializableDictionary.meta ├── Dependencies.meta ├── Editor/ │ ├── AssetCallbacks/ │ │ ├── CreateDlogGraph.cs │ │ └── CreateDlogGraph.cs.meta │ ├── AssetCallbacks.meta │ ├── DialogueGraph.Editor.asmdef │ ├── DialogueGraph.Editor.asmdef.meta │ ├── Extensions/ │ │ ├── DlogExtensions.cs │ │ ├── DlogExtensions.cs.meta │ │ ├── GUILayoutHelper.cs │ │ ├── GUILayoutHelper.cs.meta │ │ ├── GraphViewExtensions.cs │ │ ├── GraphViewExtensions.cs.meta │ │ ├── VisualElementExtensions.cs │ │ └── VisualElementExtensions.cs.meta │ ├── Extensions.meta │ ├── Graph/ │ │ ├── Attributes/ │ │ │ ├── TitleAttribute.cs │ │ │ └── TitleAttribute.cs.meta │ │ ├── Attributes.meta │ │ ├── Data/ │ │ │ ├── CopyPasteData.cs │ │ │ ├── CopyPasteData.cs.meta │ │ │ ├── DlogGraphData.cs │ │ │ ├── DlogGraphData.cs.meta │ │ │ ├── DlogGraphObject.cs │ │ │ ├── DlogGraphObject.cs.meta │ │ │ ├── NodeDrawState.cs │ │ │ ├── NodeDrawState.cs.meta │ │ │ ├── Properties/ │ │ │ │ ├── AbstractProperty.cs │ │ │ │ ├── AbstractProperty.cs.meta │ │ │ │ ├── ActorProperty.cs │ │ │ │ ├── ActorProperty.cs.meta │ │ │ │ ├── CheckProperty.cs │ │ │ │ ├── CheckProperty.cs.meta │ │ │ │ ├── TriggerProperty.cs │ │ │ │ └── TriggerProperty.cs.meta │ │ │ ├── Properties.meta │ │ │ ├── SerializedEdge.cs │ │ │ ├── SerializedEdge.cs.meta │ │ │ ├── SerializedNode.cs │ │ │ ├── SerializedNode.cs.meta │ │ │ ├── SerializedProperty.cs │ │ │ ├── SerializedProperty.cs.meta │ │ │ ├── VersionMismatchObject.cs │ │ │ └── VersionMismatchObject.cs.meta │ │ ├── Data.meta │ │ ├── Nodes/ │ │ │ ├── AbstractNode.cs │ │ │ ├── AbstractNode.cs.meta │ │ │ ├── Boolean/ │ │ │ │ ├── BinaryBooleanNode.cs │ │ │ │ ├── BinaryBooleanNode.cs.meta │ │ │ │ ├── BooleanNodes.cs │ │ │ │ ├── BooleanNodes.cs.meta │ │ │ │ ├── UnaryBooleanNode.cs │ │ │ │ └── UnaryBooleanNode.cs.meta │ │ │ ├── Boolean.meta │ │ │ ├── NodeColors.cs │ │ │ ├── NodeColors.cs.meta │ │ │ ├── NpcNode.cs │ │ │ ├── NpcNode.cs.meta │ │ │ ├── Port/ │ │ │ │ ├── DlogPort.cs │ │ │ │ ├── DlogPort.cs.meta │ │ │ │ ├── PortHelper.cs │ │ │ │ ├── PortHelper.cs.meta │ │ │ │ ├── PortType.cs │ │ │ │ └── PortType.cs.meta │ │ │ ├── Port.meta │ │ │ ├── PropertyNode.cs │ │ │ ├── PropertyNode.cs.meta │ │ │ ├── SelfNode.cs │ │ │ └── SelfNode.cs.meta │ │ ├── Nodes.meta │ │ ├── Views/ │ │ │ ├── Blackboard/ │ │ │ │ ├── BlackboardPropertyView.cs │ │ │ │ ├── BlackboardPropertyView.cs.meta │ │ │ │ ├── BlackboardProvider.cs │ │ │ │ └── BlackboardProvider.cs.meta │ │ │ ├── Blackboard.meta │ │ │ ├── DlogEditorWindow.cs │ │ │ ├── DlogEditorWindow.cs.meta │ │ │ ├── DlogGraphView.cs │ │ │ ├── DlogGraphView.cs.meta │ │ │ ├── DlogWindowEvents.cs │ │ │ ├── DlogWindowEvents.cs.meta │ │ │ ├── EdgeConnectorListener.cs │ │ │ ├── EdgeConnectorListener.cs.meta │ │ │ ├── EditorView.cs │ │ │ ├── EditorView.cs.meta │ │ │ ├── SearchWindow/ │ │ │ │ ├── SearchWindowAdapter.cs │ │ │ │ ├── SearchWindowAdapter.cs.meta │ │ │ │ ├── SearchWindowProvider.cs │ │ │ │ └── SearchWindowProvider.cs.meta │ │ │ └── SearchWindow.meta │ │ └── Views.meta │ ├── Graph.meta │ ├── Importers/ │ │ ├── DlogGraphAssetPostProcessor.cs │ │ ├── DlogGraphAssetPostProcessor.cs.meta │ │ ├── DlogGraphImporter.cs │ │ ├── DlogGraphImporter.cs.meta │ │ ├── DlogGraphImporterEditor.cs │ │ └── DlogGraphImporterEditor.cs.meta │ ├── Importers.meta │ ├── Inspector/ │ │ ├── DlogObjectEditor.cs │ │ └── DlogObjectEditor.cs.meta │ ├── Inspector.meta │ ├── Util/ │ │ ├── DialogueGraphUtility.cs │ │ ├── DialogueGraphUtility.cs.meta │ │ ├── Ref.cs │ │ ├── Ref.cs.meta │ │ ├── ResourcesUtility.cs │ │ ├── ResourcesUtility.cs.meta │ │ ├── UIElementsFactory.cs │ │ ├── UIElementsFactory.cs.meta │ │ ├── Versioning/ │ │ │ ├── Conversion/ │ │ │ │ ├── ConvertMethodAttribute.cs │ │ │ │ ├── ConvertMethodAttribute.cs.meta │ │ │ │ ├── VersionConverter.cs │ │ │ │ └── VersionConverter.cs.meta │ │ │ ├── Conversion.meta │ │ │ ├── SemVer.cs │ │ │ └── SemVer.cs.meta │ │ └── Versioning.meta │ └── Util.meta ├── Editor.meta ├── Github~/ │ ├── CODE_OF_CONDUCT.md │ └── CONTRIBUTING.md ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Resources/ │ ├── Inspector/ │ │ ├── ActorEditor.uxml │ │ ├── ActorEditor.uxml.meta │ │ ├── CheckEditor.uxml │ │ ├── CheckEditor.uxml.meta │ │ ├── DlogObjectEditor.uxml │ │ ├── DlogObjectEditor.uxml.meta │ │ ├── Styles/ │ │ │ ├── ActorEditor.uss │ │ │ ├── ActorEditor.uss.meta │ │ │ ├── CheckEditor.uss │ │ │ ├── CheckEditor.uss.meta │ │ │ ├── DlogObjectEditor.uss │ │ │ ├── DlogObjectEditor.uss.meta │ │ │ ├── TriggerEditor.uss │ │ │ └── TriggerEditor.uss.meta │ │ ├── Styles.meta │ │ ├── TriggerEditor.uxml │ │ └── TriggerEditor.uxml.meta │ ├── Inspector.meta │ ├── Styles/ │ │ ├── Graph.uss │ │ ├── Graph.uss.meta │ │ ├── Node/ │ │ │ ├── BooleanNode.uss │ │ │ ├── BooleanNode.uss.meta │ │ │ ├── CombinerNode.uss │ │ │ ├── CombinerNode.uss.meta │ │ │ ├── Node.uss │ │ │ ├── Node.uss.meta │ │ │ ├── Port.uss │ │ │ └── Port.uss.meta │ │ ├── Node.meta │ │ ├── PropertyView/ │ │ │ ├── Blackboard.uss │ │ │ ├── Blackboard.uss.meta │ │ │ ├── ReferenceNameField.uss │ │ │ └── ReferenceNameField.uss.meta │ │ └── PropertyView.meta │ ├── Styles.meta │ ├── Textures/ │ │ ├── boolean/ │ │ │ ├── AND.png.meta │ │ │ ├── NAND.png.meta │ │ │ ├── NOR.png.meta │ │ │ ├── NOT.png.meta │ │ │ ├── OR.png.meta │ │ │ ├── XNOR.png.meta │ │ │ └── XOR.png.meta │ │ ├── boolean.meta │ │ ├── checkCombinerBackgroundAnd.png.meta │ │ ├── checkCombinerBackgroundOr.png.meta │ │ ├── dloggraph_256.png.meta │ │ ├── dloggraph_error_256.psd │ │ ├── dloggraph_error_256.psd.meta │ │ └── dloggraph_runtime_256.png.meta │ └── Textures.meta ├── Resources.meta ├── Runtime/ │ ├── Data/ │ │ ├── ActorData.cs │ │ ├── ActorData.cs.meta │ │ ├── BooleanOperation.cs │ │ ├── BooleanOperation.cs.meta │ │ ├── CheckTree.cs │ │ ├── CheckTree.cs.meta │ │ ├── ConversationLine.cs │ │ ├── ConversationLine.cs.meta │ │ ├── DlogObject.cs │ │ ├── DlogObject.cs.meta │ │ ├── Edge.cs │ │ ├── Edge.cs.meta │ │ ├── Node.cs │ │ ├── Node.cs.meta │ │ ├── Properties/ │ │ │ ├── Property.cs │ │ │ ├── Property.cs.meta │ │ │ ├── PropertyType.cs │ │ │ └── PropertyType.cs.meta │ │ └── Properties.meta │ ├── Data.meta │ ├── DialogueGraph.Runtime.asmdef │ ├── DialogueGraph.Runtime.asmdef.meta │ ├── DlogObjectData.cs │ ├── DlogObjectData.cs.meta │ ├── GenericDataTypes.cs │ ├── GenericDataTypes.cs.meta │ ├── RuntimeDialogueGraph.cs │ └── RuntimeDialogueGraph.cs.meta ├── Runtime.meta ├── Samples~/ │ ├── DemoProject/ │ │ ├── Example.dlog │ │ ├── Example.dlog.meta │ │ ├── Prefabs/ │ │ │ ├── Line Entry.prefab │ │ │ └── Line Entry.prefab.meta │ │ ├── Prefabs.meta │ │ ├── Scenes/ │ │ │ ├── Demo.unity │ │ │ ├── Demo.unity.meta │ │ │ ├── DemoLightingSettings.lighting │ │ │ └── DemoLightingSettings.lighting.meta │ │ ├── Scenes.meta │ │ ├── Scripts/ │ │ │ ├── LineController.cs │ │ │ ├── LineController.cs.meta │ │ │ ├── LineEntry.cs │ │ │ ├── LineEntry.cs.meta │ │ │ ├── NPCDialogue.cs │ │ │ └── NPCDialogue.cs.meta │ │ ├── Scripts.meta │ │ ├── Sprites/ │ │ │ └── Square.png.meta │ │ └── Sprites.meta │ └── DemoProject.meta ├── package.json └── package.json.meta ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: teodorvecerdi tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: ['https://teodorvecerdi.itch.io/dialogue-graph'] ================================================ FILE: .gitignore ================================================ # Created by https://www.toptal.com/developers/gitignore/api/rider,unity # Edit at https://www.toptal.com/developers/gitignore?templates=rider,unity ### Rider ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. # .idea/artifacts # .idea/compiler.xml # .idea/jarRepositories.xml # .idea/modules.xml # .idea/*.iml # .idea/modules # *.iml # *.ipr # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser ### Unity ### # This .gitignore file should be placed at the root of your Unity project directory # # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore /[Ll]ibrary/ /[Tt]emp/ /[Oo]bj/ /[Bb]uild/ /[Bb]uilds/ /[Ll]ogs/ /[Uu]ser[Ss]ettings/ # MemoryCaptures can get excessive in size. # They also could contain extremely sensitive data /[Mm]emoryCaptures/ # Asset meta data should only be ignored when the corresponding asset is also ignored !/[Aa]ssets/**/*.meta # Uncomment this line if you wish to ignore the asset store tools plugin # /[Aa]ssets/AssetStoreTools* # Autogenerated Jetbrains Rider plugin /[Aa]ssets/Plugins/Editor/JetBrains* # Visual Studio cache directory .vs/ # Gradle cache directory .gradle/ # Autogenerated VS/MD/Consulo solution and project files ExportedObj/ .consulo/ *.csproj *.unityproj *.sln *.suo *.tmp *.user *.userprefs *.pidb *.booproj *.svd *.pdb *.mdb *.opendb *.VC.db # Unity3D generated meta files *.pidb.meta *.pdb.meta *.mdb.meta # Unity3D generated file on crash reports sysinfo.txt # Builds *.apk *.unitypackage # Crashlytics generated file # Autogenerated files InitTestScene*.unity.meta InitTestScene*.unity # End of https://www.toptal.com/developers/gitignore/api/rider,unity # Symlink to force 'Samples~' to show up in unity Samples/ Samples.meta Samples ================================================ FILE: Dependencies/SerializableCallback/.gitignore ================================================ ================================================ FILE: Dependencies/SerializableCallback/Editor/SerializableCallbackDrawer.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; [CustomPropertyDrawer(typeof(TargetConstraintAttribute))] [CustomPropertyDrawer(typeof(SerializableCallbackBase), true)] public class SerializableCallbackDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Indent label label.text = " " + label.text; #if UNITY_2019_1_OR_NEWER GUI.Box(position, ""); #else GUI.Box(position, "", (GUIStyle) "flow overlay box"); #endif position.y += 4; // Using BeginProperty / EndProperty on the parent property means that // prefab override logic works on the entire property. property.serializedObject.Update(); EditorGUI.BeginProperty(position, label, property); // Draw label Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); Rect targetRect = new Rect(pos.x, pos.y, pos.width, EditorGUIUtility.singleLineHeight); // Get target SerializedProperty targetProp = property.FindPropertyRelative("_target"); object target = targetProp.objectReferenceValue; if (attribute != null && attribute is TargetConstraintAttribute) { Type targetType = (attribute as TargetConstraintAttribute).targetType; EditorGUI.ObjectField(targetRect, targetProp, targetType, GUIContent.none); } else EditorGUI.PropertyField(targetRect, targetProp, GUIContent.none); if (target == null) { Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight); string msg = "Call not set. Execution will be slower."; EditorGUI.HelpBox(helpBoxRect, msg, MessageType.Warning); } else if (target is MonoScript) { Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight + EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing); string msg = "Assign a GameObject, Component or a ScriptableObject, not a script."; EditorGUI.HelpBox(helpBoxRect, msg, MessageType.Warning); } else { int indent = EditorGUI.indentLevel; EditorGUI.indentLevel++; // Get method name SerializedProperty methodProp = property.FindPropertyRelative("_methodName"); string methodName = methodProp.stringValue; // Get args SerializedProperty argProps = property.FindPropertyRelative("_args"); Type[] argTypes = GetArgTypes(argProps); // Get dynamic SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); bool dynamic = dynamicProp.boolValue; // Get active method MethodInfo activeMethod = GetMethod(target, methodName, argTypes); GUIContent methodlabel = new GUIContent("n/a"); if (activeMethod != null) methodlabel = new GUIContent(PrettifyMethod(activeMethod)); else if (!string.IsNullOrEmpty(methodName)) methodlabel = new GUIContent("Missing (" + PrettifyMethod(methodName, argTypes) + ")"); Rect methodRect = new Rect(position.x, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); // Method select button pos = EditorGUI.PrefixLabel(methodRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(dynamic ? "Method (dynamic)" : "Method")); if (EditorGUI.DropdownButton(pos, methodlabel, FocusType.Keyboard)) { MethodSelector(property); } if (activeMethod != null && !dynamic) { // Args ParameterInfo[] activeParameters = activeMethod.GetParameters(); Rect argRect = new Rect(position.x, methodRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); string[] types = new string[argProps.arraySize]; for (int i = 0; i < types.Length; i++) { SerializedProperty argProp = argProps.FindPropertyRelative("Array.data[" + i + "]"); GUIContent argLabel = new GUIContent(ObjectNames.NicifyVariableName(activeParameters[i].Name)); EditorGUI.BeginChangeCheck(); switch ((Arg.ArgType) argProp.FindPropertyRelative("argType").enumValueIndex) { case Arg.ArgType.Bool: EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("boolValue"), argLabel); break; case Arg.ArgType.Int: EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("intValue"), argLabel); break; case Arg.ArgType.Float: EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("floatValue"), argLabel); break; case Arg.ArgType.String: EditorGUI.PropertyField(argRect, argProp.FindPropertyRelative("stringValue"), argLabel); break; case Arg.ArgType.Object: SerializedProperty typeProp = argProp.FindPropertyRelative("_typeName"); SerializedProperty objProp = argProp.FindPropertyRelative("objectValue"); if (typeProp != null) { Type objType = Type.GetType(typeProp.stringValue, false); EditorGUI.BeginChangeCheck(); Object obj = objProp.objectReferenceValue; obj = EditorGUI.ObjectField(argRect, argLabel, obj, objType, true); if (EditorGUI.EndChangeCheck()) { objProp.objectReferenceValue = obj; } } else { EditorGUI.PropertyField(argRect, objProp, argLabel); } break; } if (EditorGUI.EndChangeCheck()) { property.FindPropertyRelative("dirty").boolValue = true; } argRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; } } EditorGUI.indentLevel = indent; } // Set indent back to what it was EditorGUI.EndProperty(); property.serializedObject.ApplyModifiedProperties(); } private class MenuItem { public GenericMenu.MenuFunction action; public string path; public GUIContent label; public MenuItem(string path, string name, GenericMenu.MenuFunction action) { this.action = action; this.label = new GUIContent(path + '/' + name); this.path = path; } } void MethodSelector(SerializedProperty property) { // Return type constraint Type returnType = null; // Arg type constraint Type[] argTypes = new Type[0]; // Get return type and argument constraints SerializableCallbackBase dummy = GetDummyFunction(property); Type[] genericTypes = dummy.GetType().BaseType.GetGenericArguments(); // SerializableEventBase is always void return type if (dummy is SerializableEventBase) { returnType = typeof(void); if (genericTypes.Length > 0) { argTypes = new Type[genericTypes.Length]; Array.Copy(genericTypes, argTypes, genericTypes.Length); } } else { if (genericTypes != null && genericTypes.Length > 0) { // The last generic argument is the return type returnType = genericTypes[genericTypes.Length - 1]; if (genericTypes.Length > 1) { argTypes = new Type[genericTypes.Length - 1]; Array.Copy(genericTypes, argTypes, genericTypes.Length - 1); } } } SerializedProperty targetProp = property.FindPropertyRelative("_target"); List dynamicItems = new List(); List staticItems = new List(); List targets = new List() { targetProp.objectReferenceValue }; if (targets[0] is Component) { targets = (targets[0] as Component).gameObject.GetComponents().ToList(); targets.Add((targetProp.objectReferenceValue as Component).gameObject); } else if (targets[0] is GameObject) { targets = (targets[0] as GameObject).GetComponents().ToList(); targets.Add(targetProp.objectReferenceValue as GameObject); } for (int c = 0; c < targets.Count; c++) { Object t = targets[c]; MethodInfo[] methods = targets[c].GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); for (int i = 0; i < methods.Length; i++) { MethodInfo method = methods[i]; // Skip methods with wrong return type if (returnType != null && method.ReturnType != returnType) continue; // Skip methods with null return type // if (method.ReturnType == typeof(void)) continue; // Skip generic methods if (method.IsGenericMethod) continue; Type[] parms = method.GetParameters().Select(x => x.ParameterType).ToArray(); // Skip methods with more than 4 args if (parms.Length > 4) continue; // Skip methods with unsupported args if (parms.Any(x => !Arg.IsSupported(x))) continue; string methodPrettyName = PrettifyMethod(methods[i]); staticItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methodPrettyName, () => SetMethod(property, t, method, false))); // Skip methods with wrong constrained args if (argTypes.Length == 0 || !Enumerable.SequenceEqual(argTypes, parms)) continue; dynamicItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methods[i].Name, () => SetMethod(property, t, method, true))); } } // Construct and display context menu GenericMenu menu = new GenericMenu(); if (dynamicItems.Count > 0) { string[] paths = dynamicItems.GroupBy(x => x.path).Select(x => x.First().path).ToArray(); foreach (string path in paths) { menu.AddItem(new GUIContent(path + "/Dynamic " + PrettifyTypes(argTypes)), false, null); } for (int i = 0; i < dynamicItems.Count; i++) { menu.AddItem(dynamicItems[i].label, false, dynamicItems[i].action); } foreach (string path in paths) { menu.AddItem(new GUIContent(path + "/ "), false, null); menu.AddItem(new GUIContent(path + "/Static parameters"), false, null); } } for (int i = 0; i < staticItems.Count; i++) { menu.AddItem(staticItems[i].label, false, staticItems[i].action); } if (menu.GetItemCount() == 0) menu.AddDisabledItem(new GUIContent("No methods with return type '" + GetTypeName(returnType) + "'")); menu.ShowAsContext(); } string PrettifyMethod(string methodName, Type[] parmTypes) { string parmnames = PrettifyTypes(parmTypes); return methodName + "(" + parmnames + ")"; } string PrettifyMethod(MethodInfo methodInfo) { if (methodInfo == null) throw new ArgumentNullException("methodInfo"); ParameterInfo[] parms = methodInfo.GetParameters(); string parmnames = PrettifyTypes(parms.Select(x => x.ParameterType).ToArray()); return GetTypeName(methodInfo.ReturnParameter.ParameterType) + " " + methodInfo.Name + "(" + parmnames + ")"; } string PrettifyTypes(Type[] types) { if (types == null) throw new ArgumentNullException("types"); return string.Join(", ", types.Select(x => GetTypeName(x)).ToArray()); } MethodInfo GetMethod(object target, string methodName, Type[] types) { MethodInfo activeMethod = target.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, null, CallingConventions.Any, types, null); return activeMethod; } private Type[] GetArgTypes(SerializedProperty argsProp) { Type[] types = new Type[argsProp.arraySize]; for (int i = 0; i < argsProp.arraySize; i++) { SerializedProperty argProp = argsProp.GetArrayElementAtIndex(i); SerializedProperty typeNameProp = argProp.FindPropertyRelative("_typeName"); if (typeNameProp != null) types[i] = Type.GetType(typeNameProp.stringValue, false); if (types[i] == null) types[i] = Arg.RealType((Arg.ArgType) argProp.FindPropertyRelative("argType").enumValueIndex); } return types; } private void SetMethod(SerializedProperty property, UnityEngine.Object target, MethodInfo methodInfo, bool dynamic) { SerializedProperty targetProp = property.FindPropertyRelative("_target"); targetProp.objectReferenceValue = target; SerializedProperty methodProp = property.FindPropertyRelative("_methodName"); methodProp.stringValue = methodInfo.Name; SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); dynamicProp.boolValue = dynamic; SerializedProperty argProp = property.FindPropertyRelative("_args"); ParameterInfo[] parameters = methodInfo.GetParameters(); argProp.arraySize = parameters.Length; for (int i = 0; i < parameters.Length; i++) { argProp.FindPropertyRelative("Array.data[" + i + "].argType").enumValueIndex = (int) Arg.FromRealType(parameters[i].ParameterType); argProp.FindPropertyRelative("Array.data[" + i + "]._typeName").stringValue = parameters[i].ParameterType.AssemblyQualifiedName; } property.FindPropertyRelative("dirty").boolValue = true; property.serializedObject.ApplyModifiedProperties(); property.serializedObject.Update(); } private static string GetTypeName(Type t) { if (t == typeof(int)) return "int"; else if (t == typeof(float)) return "float"; else if (t == typeof(string)) return "string"; else if (t == typeof(bool)) return "bool"; else if (t == typeof(void)) return "void"; else return t.Name; } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { float lineheight = EditorGUIUtility.standardVerticalSpacing + EditorGUIUtility.singleLineHeight; SerializedProperty targetProp = property.FindPropertyRelative("_target"); SerializedProperty argProps = property.FindPropertyRelative("_args"); SerializedProperty dynamicProp = property.FindPropertyRelative("_dynamic"); float height = lineheight + lineheight; if (targetProp.objectReferenceValue != null && targetProp.objectReferenceValue is MonoScript) height += lineheight; else if (targetProp.objectReferenceValue != null && !dynamicProp.boolValue) height += argProps.arraySize * lineheight; height += 8; return height; } private static SerializableCallbackBase GetDummyFunction(SerializedProperty prop) { string stringValue = prop.FindPropertyRelative("_typeName").stringValue; Type type = Type.GetType(stringValue, false); SerializableCallbackBase result; if (type == null) { return null; } else { result = (Activator.CreateInstance(type) as SerializableCallbackBase); } return result; } } ================================================ FILE: Dependencies/SerializableCallback/Editor/SerializableCallbackDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 65cd8a53f6f9cf04ea4aa8e2743322fd timeCreated: 1513845239 licenseType: Pro MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Editor/Siccity.SerializableCallback.Editor.asmdef ================================================ { "name": "Siccity.SerializableCallback.Editor", "references": [ "GUID:11a2306c728a4b843a652ec6c2f142bc" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: Dependencies/SerializableCallback/Editor/Siccity.SerializableCallback.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: a49fd1d25e23fd14e85d1cbf342bb06f AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Editor.meta ================================================ fileFormatVersion: 2 guid: 39c1d273b3e79e346a281e4a542a63a6 folderAsset: yes timeCreated: 1513845239 licenseType: Pro DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/LICENSE.md ================================================ MIT License Copyright (c) 2017 Thor Brigsted Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Dependencies/SerializableCallback/LICENSE.md.meta ================================================ fileFormatVersion: 2 guid: 664adef14643bfe44a13ce197b3a540c TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/README.md ================================================ ### SerializableCallback Lets you drag-and-drop methods with or without return values / parameters in the Unity inspector. It uses expression trees and reflection to cache a delegate on first execution. Usage is identical to UnityEvent ![unity_inspector](https://user-images.githubusercontent.com/6402525/34294989-46de127e-e70b-11e7-84f0-99bc4525a8f5.png) ```csharp public class MyClass : MonoBehaviour { //These fields are shown in the inspector public SerializableCallback callback; // supports all non-void return types public Condition condition; // supports bool return types only public GetProduct getProduct; // supports MyProduct return types only void Start() { // Callbacks can be invoked with or without parameters, and with different types Debug.Log(callback.Invoke()); // returns object Debug.Log(condition.Invoke()); // returns bool Debug.Log(getProduct.Invoke(2)); // returns MyProduct } // As with UnityEvents, custom callbacks must have a non-generic wrapper class marked as [Serializable] in order to be serialized by Unity [Serializable] public class Condition : SerializableCallback {} // Last generic type parameter is the return type, staying consistent with System.Func [Serializable] public class GetProduct : SerializableCallback {} } ``` | Performance (100000 iterations) | Time | | -------------------------------------------- | --------- | | bool Method(float) | 00.00304s | | SerializedCallback (Persistent) | 00.01026s | | SerializedCallback (Dynamic) | 00.00797s | ### Installing with Unity Package Manager To install this project as a dependency using the Unity Package Manager, add the following line to your project's `manifest.json`: ``` "com.github.siccity.serializablecallback": "git+https://github.com/Siccity/SerializableCallback.git" ``` Join the [Discord](https://discord.gg/qgPrHv4 "Join Discord server") server to leave feedback or get support. ================================================ FILE: Dependencies/SerializableCallback/README.md.meta ================================================ fileFormatVersion: 2 guid: b5a8c7667bbebba4ca6545be57800251 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/Attributes/TargetConstraintAttribute.cs ================================================ using UnityEngine; using System; /// Add to fields of your class extending SerializableCallbackBase to limit which types can be assigned to it. public class TargetConstraintAttribute : PropertyAttribute { public Type targetType; /// Add to fields of your class extending SerializableCallbackBase to limit which types can be assigned to it. public TargetConstraintAttribute(Type targetType) { this.targetType = targetType; } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/Attributes/TargetConstraintAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: 4b9b7d20cf54ac6489b84d21c29a4c69 timeCreated: 1536132736 licenseType: Pro MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/Attributes.meta ================================================ fileFormatVersion: 2 guid: 4fd350e49301e4445a1cbe580fe9eec7 folderAsset: yes timeCreated: 1536132750 licenseType: Pro DefaultImporter: userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableCallback.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class InvokableCallback : InvokableCallbackBase { public Func func; public TReturn Invoke() { return func(); } public override TReturn Invoke(params object[] args) { return func(); } /// Constructor public InvokableCallback(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { func = () => default(TReturn); } else { func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); } } } public class InvokableCallback : InvokableCallbackBase { public Func func; public TReturn Invoke(T0 arg0) { return func(arg0); } public override TReturn Invoke(params object[] args) { // Convert from special "unity-nulls" to true null if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; return func((T0) args[0]); } /// Constructor public InvokableCallback(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { func = x => default(TReturn); } else { func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); } } } public class InvokableCallback : InvokableCallbackBase { public Func func; public TReturn Invoke(T0 arg0, T1 arg1) { return func(arg0, arg1); } public override TReturn Invoke(params object[] args) { // Convert from special "unity-nulls" to true null if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; return func((T0) args[0], (T1) args[1]); } /// Constructor public InvokableCallback(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { func = (x, y) => default(TReturn); } else { func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); } } } public class InvokableCallback : InvokableCallbackBase { public Func func; public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2) { return func(arg0, arg1, arg2); } public override TReturn Invoke(params object[] args) { // Convert from special "unity-nulls" to true null if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; if (args[2] is UnityEngine.Object && (UnityEngine.Object) args[2] == null) args[2] = null; return func((T0) args[0], (T1) args[1], (T2) args[2]); } /// Constructor public InvokableCallback(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { func = (x, y, z) => default(TReturn); } else { func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); } } } public class InvokableCallback : InvokableCallbackBase { public Func func; public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { return func(arg0, arg1, arg2, arg3); } public override TReturn Invoke(params object[] args) { // Convert from special "unity-nulls" to true null if (args[0] is UnityEngine.Object && (UnityEngine.Object) args[0] == null) args[0] = null; if (args[1] is UnityEngine.Object && (UnityEngine.Object) args[1] == null) args[1] = null; if (args[2] is UnityEngine.Object && (UnityEngine.Object) args[2] == null) args[2] = null; if (args[3] is UnityEngine.Object && (UnityEngine.Object) args[3] == null) args[3] = null; return func((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]); } /// Constructor public InvokableCallback(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { func = (x, y, z, w) => default(TReturn); } else { func = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), target, methodName); } } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableCallback.cs.meta ================================================ fileFormatVersion: 2 guid: ca67a6ce15814b743b8e123c175ce649 timeCreated: 1515587326 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableCallbackBase.cs ================================================ public abstract class InvokableCallbackBase { public abstract TReturn Invoke(params object[] args); } ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableCallbackBase.cs.meta ================================================ fileFormatVersion: 2 guid: 9147523dbcc2f2f46878180063444518 timeCreated: 1515583421 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableEvent.cs ================================================ using System; public class InvokableEvent : InvokableEventBase { public System.Action action; public void Invoke() { action(); } public override void Invoke(params object[] args) { action(); } /// Constructor public InvokableEvent(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { action = () => { }; } else { action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); } } } public class InvokableEvent : InvokableEventBase { public Action action; public void Invoke(T0 arg0) { action(arg0); } public override void Invoke(params object[] args) { action((T0) args[0]); } /// Constructor public InvokableEvent(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { action = x => { }; } else { action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); } } } public class InvokableEvent : InvokableEventBase { public Action action; public void Invoke(T0 arg0, T1 arg1) { action(arg0, arg1); } public override void Invoke(params object[] args) { action((T0) args[0], (T1) args[1]); } /// Constructor public InvokableEvent(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { action = (x, y) => { }; } else { action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); } } } public class InvokableEvent : InvokableEventBase { public Action action; public void Invoke(T0 arg0, T1 arg1, T2 arg2) { action(arg0, arg1, arg2); } public override void Invoke(params object[] args) { action((T0) args[0], (T1) args[1], (T2) args[2]); } /// Constructor public InvokableEvent(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { action = (x, y, z) => { }; } else { action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); } } } public class InvokableEvent : InvokableEventBase { public Action action; public void Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { action(arg0, arg1, arg2, arg3); } public override void Invoke(params object[] args) { action((T0) args[0], (T1) args[1], (T2) args[2], (T3) args[3]); } /// Constructor public InvokableEvent(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { action = (x, y, z, w) => { }; } else { action = (System.Action) System.Delegate.CreateDelegate(typeof(System.Action), target, methodName); } } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 51f8a42e6f95b694cb28ca372e32aef3 timeCreated: 1515748293 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableEventBase.cs ================================================ public abstract class InvokableEventBase { public abstract void Invoke(params object[] args); } ================================================ FILE: Dependencies/SerializableCallback/Runtime/InvokableEventBase.cs.meta ================================================ fileFormatVersion: 2 guid: e958262ec96656d459752d5df5faa52e timeCreated: 1515748285 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableCallback.cs ================================================ using System; using System.Linq.Expressions; using System.Reflection; using UnityEngine; public abstract class SerializableCallback : SerializableCallbackBase { public TReturn Invoke() { if (func == null) Cache(); if (_dynamic) { InvokableCallback call = func as InvokableCallback; return call.Invoke(); } else { return func.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { func = new InvokableCallback(null, null); } else { if (_dynamic) { func = new InvokableCallback(target, methodName); } else { func = GetPersistentMethod(); } } } } public abstract class SerializableCallback : SerializableCallbackBase { public TReturn Invoke(T0 arg0) { if (func == null) Cache(); if (_dynamic) { InvokableCallback call = func as InvokableCallback; return call.Invoke(arg0); } else { return func.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { func = new InvokableCallback(null, null); } else { if (_dynamic) { func = new InvokableCallback(target, methodName); } else { func = GetPersistentMethod(); } } } } public abstract class SerializableCallback : SerializableCallbackBase { public TReturn Invoke(T0 arg0, T1 arg1) { if (func == null) Cache(); if (_dynamic) { InvokableCallback call = func as InvokableCallback; return call.Invoke(arg0, arg1); } else { return func.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { func = new InvokableCallback(null, null); } else { if (_dynamic) { func = new InvokableCallback(target, methodName); } else { func = GetPersistentMethod(); } } } } public abstract class SerializableCallback : SerializableCallbackBase { public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2) { if (func == null) Cache(); if (_dynamic) { InvokableCallback call = func as InvokableCallback; return call.Invoke(arg0, arg1, arg2); } else { return func.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { func = new InvokableCallback(null, null); } else { if (_dynamic) { func = new InvokableCallback(target, methodName); } else { func = GetPersistentMethod(); } } } } public abstract class SerializableCallback : SerializableCallbackBase { public TReturn Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { if (func == null) Cache(); if (_dynamic) { InvokableCallback call = func as InvokableCallback; return call.Invoke(arg0, arg1, arg2, arg3); } else { return func.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { func = new InvokableCallback(null, null); } else { if (_dynamic) { func = new InvokableCallback(target, methodName); } else { func = GetPersistentMethod(); } } } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableCallback.cs.meta ================================================ fileFormatVersion: 2 guid: dc926a8278d45964e842b3ee4b9e593b timeCreated: 1513845239 licenseType: Pro MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableCallbackBase.cs ================================================ using System; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; using UnityEngine; using Object = UnityEngine.Object; public abstract class SerializableCallbackBase : SerializableCallbackBase { public InvokableCallbackBase func; public override void ClearCache() { base.ClearCache(); func = null; } protected InvokableCallbackBase GetPersistentMethod() { Type[] types = new Type[ArgRealTypes.Length + 1]; Array.Copy(ArgRealTypes, types, ArgRealTypes.Length); types[types.Length - 1] = typeof(TReturn); Type genericType = null; switch (types.Length) { case 1: genericType = typeof(InvokableCallback<>).MakeGenericType(types); break; case 2: genericType = typeof(InvokableCallback<,>).MakeGenericType(types); break; case 3: genericType = typeof(InvokableCallback<, ,>).MakeGenericType(types); break; case 4: genericType = typeof(InvokableCallback<, , ,>).MakeGenericType(types); break; case 5: genericType = typeof(InvokableCallback<, , , ,>).MakeGenericType(types); break; default: throw new ArgumentException(types.Length + "args"); } return Activator.CreateInstance(genericType, new object[] { target, methodName }) as InvokableCallbackBase; } } /// An inspector-friendly serializable function [System.Serializable] public abstract class SerializableCallbackBase : ISerializationCallbackReceiver { /// Target object public Object target { get { return _target; } set { _target = value; ClearCache(); } } /// Target method name public string methodName { get { return _methodName; } set { _methodName = value; ClearCache(); } } public object[] Args { get { return args != null ? args : args = _args.Select(x => x.GetValue()).ToArray(); } } public object[] args; public Type[] ArgTypes { get { return argTypes != null ? argTypes : argTypes = _args.Select(x => Arg.RealType(x.argType)).ToArray(); } } public Type[] argTypes; public Type[] ArgRealTypes { get { return argRealTypes != null ? argRealTypes : argRealTypes = _args.Select(x => Type.GetType(x._typeName)).ToArray(); } } public Type[] argRealTypes; public bool dynamic { get { return _dynamic; } set { _dynamic = value; ClearCache(); } } [SerializeField] protected Object _target; [SerializeField] protected string _methodName; [SerializeField] protected Arg[] _args; [SerializeField] protected bool _dynamic; #pragma warning disable 0414 [SerializeField] private string _typeName; #pragma warning restore 0414 [SerializeField] private bool dirty; #if UNITY_EDITOR protected SerializableCallbackBase() { _typeName = base.GetType().AssemblyQualifiedName; } #endif public virtual void ClearCache() { argTypes = null; args = null; } public void SetMethod(Object target, string methodName, bool dynamic, params Arg[] args) { _target = target; _methodName = methodName; _dynamic = dynamic; _args = args; ClearCache(); } protected abstract void Cache(); public void OnBeforeSerialize() { #if UNITY_EDITOR if (dirty) { ClearCache(); dirty = false; } #endif } public void OnAfterDeserialize() { #if UNITY_EDITOR _typeName = base.GetType().AssemblyQualifiedName; #endif } } [System.Serializable] public struct Arg { public enum ArgType { Unsupported, Bool, Int, Float, String, Object } public bool boolValue; public int intValue; public float floatValue; public string stringValue; public Object objectValue; public ArgType argType; public string _typeName; public object GetValue() { return GetValue(argType); } public object GetValue(ArgType type) { switch (type) { case ArgType.Bool: return boolValue; case ArgType.Int: return intValue; case ArgType.Float: return floatValue; case ArgType.String: return stringValue; case ArgType.Object: return objectValue; default: return null; } } public static Type RealType(ArgType type) { switch (type) { case ArgType.Bool: return typeof(bool); case ArgType.Int: return typeof(int); case ArgType.Float: return typeof(float); case ArgType.String: return typeof(string); case ArgType.Object: return typeof(Object); default: return null; } } public static ArgType FromRealType(Type type) { if (type == typeof(bool)) return ArgType.Bool; else if (type == typeof(int)) return ArgType.Int; else if (type == typeof(float)) return ArgType.Float; else if (type == typeof(String)) return ArgType.String; else if (typeof(Object).IsAssignableFrom(type)) return ArgType.Object; else return ArgType.Unsupported; } public static bool IsSupported(Type type) { return FromRealType(type) != ArgType.Unsupported; } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableCallbackBase.cs.meta ================================================ fileFormatVersion: 2 guid: 7281861ef496a34429213165496d8cf3 timeCreated: 1513845239 licenseType: Pro MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableEvent.cs ================================================ [System.Serializable] public class SerializableEvent : SerializableEventBase { public void Invoke() { if (invokable == null) Cache(); if (_dynamic) { InvokableEvent call = invokable as InvokableEvent; call.Invoke(); } else { invokable.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { invokable = new InvokableEvent(null, null); } else { if (_dynamic) { invokable = new InvokableEvent(target, methodName); } else { invokable = GetPersistentMethod(); } } } } public abstract class SerializableEvent : SerializableEventBase { public void Invoke(T0 arg0) { if (invokable == null) Cache(); if (_dynamic) { InvokableEvent call = invokable as InvokableEvent; call.Invoke(arg0); } else { invokable.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { invokable = new InvokableEvent(null, null); } else { if (_dynamic) { invokable = new InvokableEvent(target, methodName); } else { invokable = GetPersistentMethod(); } } } } public abstract class SerializableEvent : SerializableEventBase { public void Invoke(T0 arg0, T1 arg1) { if (invokable == null) Cache(); if (_dynamic) { InvokableEvent call = invokable as InvokableEvent; call.Invoke(arg0, arg1); } else { invokable.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { invokable = new InvokableEvent(null, null); } else { if (_dynamic) { invokable = new InvokableEvent(target, methodName); } else { invokable = GetPersistentMethod(); } } } } public abstract class SerializableEvent : SerializableEventBase { public void Invoke(T0 arg0, T1 arg1, T2 arg2) { if (invokable == null) Cache(); if (_dynamic) { InvokableEvent call = invokable as InvokableEvent; call.Invoke(arg0, arg1, arg2); } else { invokable.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { invokable = new InvokableEvent(null, null); } else { if (_dynamic) { invokable = new InvokableEvent(target, methodName); } else { invokable = GetPersistentMethod(); } } } } public abstract class SerializableEvent : SerializableEventBase { public void Invoke(T0 arg0, T1 arg1, T2 arg2, T3 arg3) { if (invokable == null) Cache(); if (_dynamic) { InvokableEvent call = invokable as InvokableEvent; call.Invoke(arg0, arg1, arg2, arg3); } else { invokable.Invoke(Args); } } protected override void Cache() { if (_target == null || string.IsNullOrEmpty(_methodName)) { invokable = new InvokableEvent(null, null); } else { if (_dynamic) { invokable = new InvokableEvent(target, methodName); } else { invokable = GetPersistentMethod(); } } } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableEvent.cs.meta ================================================ fileFormatVersion: 2 guid: 874a1a13ec4740a4387fe34d59931868 timeCreated: 1515747693 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableEventBase.cs ================================================ using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public abstract class SerializableEventBase : SerializableCallbackBase { public InvokableEventBase invokable; public override void ClearCache() { base.ClearCache(); invokable = null; } protected InvokableEventBase GetPersistentMethod() { Type[] types = new Type[ArgTypes.Length]; Array.Copy(ArgTypes, types, ArgTypes.Length); Type genericType = null; switch (types.Length) { case 0: genericType = typeof(InvokableEvent); break; case 1: genericType = typeof(InvokableEvent<>).MakeGenericType(types); break; case 2: genericType = typeof(InvokableEvent<,>).MakeGenericType(types); break; case 3: genericType = typeof(InvokableEvent<, ,>).MakeGenericType(types); break; case 4: genericType = typeof(InvokableEvent<, , ,>).MakeGenericType(types); break; default: throw new ArgumentException(types.Length + "args"); } return Activator.CreateInstance(genericType, new object[] { target, methodName }) as InvokableEventBase; } } ================================================ FILE: Dependencies/SerializableCallback/Runtime/SerializableEventBase.cs.meta ================================================ fileFormatVersion: 2 guid: e5856b88cee94a64c95101c3f3de4754 timeCreated: 1515747887 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/Siccity.SerializableCallback.asmdef ================================================ { "name": "Siccity.SerializableCallback", "references": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: Dependencies/SerializableCallback/Runtime/Siccity.SerializableCallback.asmdef.meta ================================================ fileFormatVersion: 2 guid: 11a2306c728a4b843a652ec6c2f142bc AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime/Test.cs ================================================ using System; using System.Diagnostics; using UnityEngine; public class Test : MonoBehaviour { const int ITERATIONS = 100000; public float f = 0.5f; public string s; public System.Func RegularDelegate; public System.Func DynamicDelegate; public Condition condition; public SerializableEvent ev; void Start() { RegularDelegate = TestMethod; DynamicDelegate = (System.Func) System.Delegate.CreateDelegate(typeof(System.Func), this, "TestMethod"); condition.Invoke(f); } void Update() { var method = Stopwatch.StartNew(); bool methodb = false; for (int i = 0; i < ITERATIONS; ++i) { methodb = TestMethod(f); } method.Stop(); var regularDelegate = Stopwatch.StartNew(); bool regularDelegateb = false; for (int i = 0; i < ITERATIONS; ++i) { regularDelegateb = RegularDelegate(f); } regularDelegate.Stop(); var dynamicDelegate = Stopwatch.StartNew(); bool dynamicDelegateb = false; for (int i = 0; i < ITERATIONS; ++i) { dynamicDelegateb = DynamicDelegate(f); } dynamicDelegate.Stop(); var serializedDelegate = Stopwatch.StartNew(); bool serializedDelegateb = false; for (int i = 0; i < ITERATIONS; ++i) { serializedDelegateb = condition.Invoke(f); } serializedDelegate.Stop(); var serializedEvent = Stopwatch.StartNew(); for (int i = 0; i < ITERATIONS; ++i) { ev.Invoke(); } serializedEvent.Stop(); UnityEngine.Debug.Log("Method: " + methodb + method.Elapsed); UnityEngine.Debug.Log("RegularDelegate: " + regularDelegateb + regularDelegate.Elapsed); UnityEngine.Debug.Log("DynamicDelegate: " + dynamicDelegateb + dynamicDelegate.Elapsed); UnityEngine.Debug.Log("SerializedCallback: " + serializedDelegateb + serializedDelegate.Elapsed); UnityEngine.Debug.Log("SerializedEvent: " + serializedEvent.Elapsed); } public bool TestMethod(float f) { return f > 0.5f; } public bool TestMethod(string a) { return string.IsNullOrEmpty(a); } public bool TestMethod2(float f, string a) { return f > 0.5f && string.IsNullOrEmpty(a); } public void TestMethod2(string a) { s = a; } } [Serializable] public class Condition : SerializableCallback { } ================================================ FILE: Dependencies/SerializableCallback/Runtime/Test.cs.meta ================================================ fileFormatVersion: 2 guid: 933cfc79696bbd74ca51c70a8d61ae8d timeCreated: 1514107717 licenseType: Free MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/Runtime.meta ================================================ fileFormatVersion: 2 guid: a6c274949c3a3494db6ab4e33e996353 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback/package.json ================================================ { "name": "com.github.siccity.serializablecallback", "description": "UnityEvent and System.Func had a child. Lets you drag-and-drop methods with or without return values / parameters in the Unity inspector. It uses expression trees and reflection to cache a delegate on first execution. Usage is identical to UnityEvent", "version": "1.0.0", "unity": "2018.1", "displayName": "SerializableCallback", "author": { "name": "Thor Brigsted", "url": "http://thorbrigsted.com/" } } ================================================ FILE: Dependencies/SerializableCallback/package.json.meta ================================================ fileFormatVersion: 2 guid: 70b54a564f424a742af19bd2af6873c5 TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableCallback.meta ================================================ fileFormatVersion: 2 guid: e9d9d85b74d78594b85a4a679b74607f folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary/Editor/SerializableDictionary.Editor.asmdef ================================================ { "name": "SerializableDictionary.Editor", "rootNamespace": "", "references": [ "GUID:479678a6fc2d434439a70c037334ff05" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: Dependencies/SerializableDictionary/Editor/SerializableDictionary.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 5debd524d9fe37b44aa7aede833a8eb7 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs ================================================ using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Reflection; using System; public class SerializableDictionaryPropertyDrawer : PropertyDrawer { const string KeysFieldName = "m_keys"; const string ValuesFieldName = "m_values"; protected const float IndentWidth = 15f; static GUIContent s_iconPlus = IconContent ("Toolbar Plus", "Add entry"); static GUIContent s_iconMinus = IconContent ("Toolbar Minus", "Remove entry"); static GUIContent s_warningIconConflict = IconContent ("console.warnicon.sml", "Conflicting key, this entry will be lost"); static GUIContent s_warningIconOther = IconContent ("console.infoicon.sml", "Conflicting key"); static GUIContent s_warningIconNull = IconContent ("console.warnicon.sml", "Null key, this entry will be lost"); static GUIStyle s_buttonStyle = GUIStyle.none; static GUIContent s_tempContent = new GUIContent(); class ConflictState { public object conflictKey = null; public object conflictValue = null; public int conflictIndex = -1 ; public int conflictOtherIndex = -1 ; public bool conflictKeyPropertyExpanded = false; public bool conflictValuePropertyExpanded = false; public float conflictLineHeight = 0f; } struct PropertyIdentity { public PropertyIdentity(SerializedProperty property) { this.instance = property.serializedObject.targetObject; this.propertyPath = property.propertyPath; } public UnityEngine.Object instance; public string propertyPath; } static Dictionary s_conflictStateDict = new Dictionary(); enum Action { None, Add, Remove } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { label = EditorGUI.BeginProperty(position, label, property); Action buttonAction = Action.None; int buttonActionIndex = 0; var keyArrayProperty = property.FindPropertyRelative(KeysFieldName); var valueArrayProperty = property.FindPropertyRelative(ValuesFieldName); ConflictState conflictState = GetConflictState(property); if(conflictState.conflictIndex != -1) { keyArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); var keyProperty = keyArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); SetPropertyValue(keyProperty, conflictState.conflictKey); keyProperty.isExpanded = conflictState.conflictKeyPropertyExpanded; valueArrayProperty.InsertArrayElementAtIndex(conflictState.conflictIndex); var valueProperty = valueArrayProperty.GetArrayElementAtIndex(conflictState.conflictIndex); SetPropertyValue(valueProperty, conflictState.conflictValue); valueProperty.isExpanded = conflictState.conflictValuePropertyExpanded; } var buttonWidth = s_buttonStyle.CalcSize(s_iconPlus).x; var labelPosition = position; labelPosition.height = EditorGUIUtility.singleLineHeight; if (property.isExpanded) labelPosition.xMax -= s_buttonStyle.CalcSize(s_iconPlus).x; EditorGUI.PropertyField(labelPosition, property, label, false); // property.isExpanded = EditorGUI.Foldout(labelPosition, property.isExpanded, label); if (property.isExpanded) { var buttonPosition = position; buttonPosition.xMin = buttonPosition.xMax - buttonWidth; buttonPosition.height = EditorGUIUtility.singleLineHeight; EditorGUI.BeginDisabledGroup(conflictState.conflictIndex != -1); if(GUI.Button(buttonPosition, s_iconPlus, s_buttonStyle)) { buttonAction = Action.Add; buttonActionIndex = keyArrayProperty.arraySize; } EditorGUI.EndDisabledGroup(); EditorGUI.indentLevel++; var linePosition = position; linePosition.y += EditorGUIUtility.singleLineHeight; linePosition.xMax -= buttonWidth; foreach(var entry in EnumerateEntries(keyArrayProperty, valueArrayProperty)) { var keyProperty = entry.keyProperty; var valueProperty = entry.valueProperty; int i = entry.index; float lineHeight = DrawKeyValueLine(keyProperty, valueProperty, linePosition, i); buttonPosition = linePosition; buttonPosition.x = linePosition.xMax; buttonPosition.height = EditorGUIUtility.singleLineHeight; if(GUI.Button(buttonPosition, s_iconMinus, s_buttonStyle)) { buttonAction = Action.Remove; buttonActionIndex = i; } if(i == conflictState.conflictIndex && conflictState.conflictOtherIndex == -1) { var iconPosition = linePosition; iconPosition.size = s_buttonStyle.CalcSize(s_warningIconNull); GUI.Label(iconPosition, s_warningIconNull); } else if(i == conflictState.conflictIndex) { var iconPosition = linePosition; iconPosition.size = s_buttonStyle.CalcSize(s_warningIconConflict); GUI.Label(iconPosition, s_warningIconConflict); } else if(i == conflictState.conflictOtherIndex) { var iconPosition = linePosition; iconPosition.size = s_buttonStyle.CalcSize(s_warningIconOther); GUI.Label(iconPosition, s_warningIconOther); } linePosition.y += lineHeight; } EditorGUI.indentLevel--; } if(buttonAction == Action.Add) { keyArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); valueArrayProperty.InsertArrayElementAtIndex(buttonActionIndex); } else if(buttonAction == Action.Remove) { DeleteArrayElementAtIndex(keyArrayProperty, buttonActionIndex); DeleteArrayElementAtIndex(valueArrayProperty, buttonActionIndex); } conflictState.conflictKey = null; conflictState.conflictValue = null; conflictState.conflictIndex = -1; conflictState.conflictOtherIndex = -1; conflictState.conflictLineHeight = 0f; conflictState.conflictKeyPropertyExpanded = false; conflictState.conflictValuePropertyExpanded = false; foreach(var entry1 in EnumerateEntries(keyArrayProperty, valueArrayProperty)) { var keyProperty1 = entry1.keyProperty; int i = entry1.index; object keyProperty1Value = GetPropertyValue(keyProperty1); if(keyProperty1Value == null) { var valueProperty1 = entry1.valueProperty; SaveProperty(keyProperty1, valueProperty1, i, -1, conflictState); DeleteArrayElementAtIndex(valueArrayProperty, i); DeleteArrayElementAtIndex(keyArrayProperty, i); break; } foreach(var entry2 in EnumerateEntries(keyArrayProperty, valueArrayProperty, i + 1)) { var keyProperty2 = entry2.keyProperty; int j = entry2.index; object keyProperty2Value = GetPropertyValue(keyProperty2); if(ComparePropertyValues(keyProperty1Value, keyProperty2Value)) { var valueProperty2 = entry2.valueProperty; SaveProperty(keyProperty2, valueProperty2, j, i, conflictState); DeleteArrayElementAtIndex(keyArrayProperty, j); DeleteArrayElementAtIndex(valueArrayProperty, j); goto breakLoops; } } } breakLoops: EditorGUI.EndProperty(); } static float DrawKeyValueLine(SerializedProperty keyProperty, SerializedProperty valueProperty, Rect linePosition, int index) { bool keyCanBeExpanded = CanPropertyBeExpanded(keyProperty); bool valueCanBeExpanded = CanPropertyBeExpanded(valueProperty); if(!keyCanBeExpanded && valueCanBeExpanded) { return DrawKeyValueLineExpand(keyProperty, valueProperty, linePosition); } else { var keyLabel = keyCanBeExpanded ? ("Key " + index.ToString()) : ""; var valueLabel = valueCanBeExpanded ? ("Value " + index.ToString()) : ""; return DrawKeyValueLineSimple(keyProperty, valueProperty, keyLabel, valueLabel, linePosition); } } static float DrawKeyValueLineSimple(SerializedProperty keyProperty, SerializedProperty valueProperty, string keyLabel, string valueLabel, Rect linePosition) { float labelWidth = EditorGUIUtility.labelWidth; float labelWidthRelative = labelWidth / linePosition.width; float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); var keyPosition = linePosition; keyPosition.height = keyPropertyHeight; keyPosition.width = labelWidth - IndentWidth; EditorGUIUtility.labelWidth = keyPosition.width * labelWidthRelative; EditorGUI.PropertyField(keyPosition, keyProperty, TempContent(keyLabel), true); float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); var valuePosition = linePosition; valuePosition.height = valuePropertyHeight; valuePosition.xMin += labelWidth; EditorGUIUtility.labelWidth = valuePosition.width * labelWidthRelative; EditorGUI.indentLevel--; EditorGUI.PropertyField(valuePosition, valueProperty, TempContent(valueLabel), true); EditorGUI.indentLevel++; EditorGUIUtility.labelWidth = labelWidth; return Mathf.Max(keyPropertyHeight, valuePropertyHeight); } static float DrawKeyValueLineExpand(SerializedProperty keyProperty, SerializedProperty valueProperty, Rect linePosition) { float labelWidth = EditorGUIUtility.labelWidth; float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); var keyPosition = linePosition; keyPosition.height = keyPropertyHeight; keyPosition.width = labelWidth - IndentWidth; EditorGUI.PropertyField(keyPosition, keyProperty, GUIContent.none, true); float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); var valuePosition = linePosition; valuePosition.height = valuePropertyHeight; EditorGUI.PropertyField(valuePosition, valueProperty, GUIContent.none, true); EditorGUIUtility.labelWidth = labelWidth; return Mathf.Max(keyPropertyHeight, valuePropertyHeight); } static bool CanPropertyBeExpanded(SerializedProperty property) { switch(property.propertyType) { case SerializedPropertyType.Generic: case SerializedPropertyType.Vector4: case SerializedPropertyType.Quaternion: return true; default: return false; } } static void SaveProperty(SerializedProperty keyProperty, SerializedProperty valueProperty, int index, int otherIndex, ConflictState conflictState) { conflictState.conflictKey = GetPropertyValue(keyProperty); conflictState.conflictValue = GetPropertyValue(valueProperty); float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); float lineHeight = Mathf.Max(keyPropertyHeight, valuePropertyHeight); conflictState.conflictLineHeight = lineHeight; conflictState.conflictIndex = index; conflictState.conflictOtherIndex = otherIndex; conflictState.conflictKeyPropertyExpanded = keyProperty.isExpanded; conflictState.conflictValuePropertyExpanded = valueProperty.isExpanded; } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { float propertyHeight = EditorGUIUtility.singleLineHeight; if (property.isExpanded) { var keysProperty = property.FindPropertyRelative(KeysFieldName); var valuesProperty = property.FindPropertyRelative(ValuesFieldName); foreach(var entry in EnumerateEntries(keysProperty, valuesProperty)) { var keyProperty = entry.keyProperty; var valueProperty = entry.valueProperty; float keyPropertyHeight = EditorGUI.GetPropertyHeight(keyProperty); float valuePropertyHeight = EditorGUI.GetPropertyHeight(valueProperty); float lineHeight = Mathf.Max(keyPropertyHeight, valuePropertyHeight); propertyHeight += lineHeight; } ConflictState conflictState = GetConflictState(property); if(conflictState.conflictIndex != -1) { propertyHeight += conflictState.conflictLineHeight; } } return propertyHeight; } static ConflictState GetConflictState(SerializedProperty property) { ConflictState conflictState; PropertyIdentity propId = new PropertyIdentity(property); if(!s_conflictStateDict.TryGetValue(propId, out conflictState)) { conflictState = new ConflictState(); s_conflictStateDict.Add(propId, conflictState); } return conflictState; } static Dictionary s_serializedPropertyValueAccessorsDict; static SerializableDictionaryPropertyDrawer() { Dictionary serializedPropertyValueAccessorsNameDict = new Dictionary() { { SerializedPropertyType.Integer, "intValue" }, { SerializedPropertyType.Boolean, "boolValue" }, { SerializedPropertyType.Float, "floatValue" }, { SerializedPropertyType.String, "stringValue" }, { SerializedPropertyType.Color, "colorValue" }, { SerializedPropertyType.ObjectReference, "objectReferenceValue" }, { SerializedPropertyType.LayerMask, "intValue" }, { SerializedPropertyType.Enum, "intValue" }, { SerializedPropertyType.Vector2, "vector2Value" }, { SerializedPropertyType.Vector3, "vector3Value" }, { SerializedPropertyType.Vector4, "vector4Value" }, { SerializedPropertyType.Rect, "rectValue" }, { SerializedPropertyType.ArraySize, "intValue" }, { SerializedPropertyType.Character, "intValue" }, { SerializedPropertyType.AnimationCurve, "animationCurveValue" }, { SerializedPropertyType.Bounds, "boundsValue" }, { SerializedPropertyType.Quaternion, "quaternionValue" }, }; Type serializedPropertyType = typeof(SerializedProperty); s_serializedPropertyValueAccessorsDict = new Dictionary(); BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; foreach(var kvp in serializedPropertyValueAccessorsNameDict) { PropertyInfo propertyInfo = serializedPropertyType.GetProperty(kvp.Value, flags); s_serializedPropertyValueAccessorsDict.Add(kvp.Key, propertyInfo); } } static GUIContent IconContent(string name, string tooltip) { var builtinIcon = EditorGUIUtility.IconContent (name); return new GUIContent(builtinIcon.image, tooltip); } static GUIContent TempContent(string text) { s_tempContent.text = text; return s_tempContent; } static void DeleteArrayElementAtIndex(SerializedProperty arrayProperty, int index) { var property = arrayProperty.GetArrayElementAtIndex(index); // if(arrayProperty.arrayElementType.StartsWith("PPtr<$")) if(property.propertyType == SerializedPropertyType.ObjectReference) { property.objectReferenceValue = null; } arrayProperty.DeleteArrayElementAtIndex(index); } public static object GetPropertyValue(SerializedProperty p) { PropertyInfo propertyInfo; if(s_serializedPropertyValueAccessorsDict.TryGetValue(p.propertyType, out propertyInfo)) { return propertyInfo.GetValue(p, null); } else { if(p.isArray) return GetPropertyValueArray(p); else return GetPropertyValueGeneric(p); } } static void SetPropertyValue(SerializedProperty p, object v) { PropertyInfo propertyInfo; if(s_serializedPropertyValueAccessorsDict.TryGetValue(p.propertyType, out propertyInfo)) { propertyInfo.SetValue(p, v, null); } else { if(p.isArray) SetPropertyValueArray(p, v); else SetPropertyValueGeneric(p, v); } } static object GetPropertyValueArray(SerializedProperty property) { object[] array = new object[property.arraySize]; for(int i = 0; i < property.arraySize; i++) { SerializedProperty item = property.GetArrayElementAtIndex(i); array[i] = GetPropertyValue(item); } return array; } static object GetPropertyValueGeneric(SerializedProperty property) { Dictionary dict = new Dictionary(); var iterator = property.Copy(); if(iterator.Next(true)) { var end = property.GetEndProperty(); do { string name = iterator.name; object value = GetPropertyValue(iterator); dict.Add(name, value); } while(iterator.Next(false) && iterator.propertyPath != end.propertyPath); } return dict; } static void SetPropertyValueArray(SerializedProperty property, object v) { object[] array = (object[]) v; property.arraySize = array.Length; for(int i = 0; i < property.arraySize; i++) { SerializedProperty item = property.GetArrayElementAtIndex(i); SetPropertyValue(item, array[i]); } } static void SetPropertyValueGeneric(SerializedProperty property, object v) { Dictionary dict = (Dictionary) v; var iterator = property.Copy(); if(iterator.Next(true)) { var end = property.GetEndProperty(); do { string name = iterator.name; SetPropertyValue(iterator, dict[name]); } while(iterator.Next(false) && iterator.propertyPath != end.propertyPath); } } static bool ComparePropertyValues(object value1, object value2) { if(value1 is Dictionary && value2 is Dictionary) { var dict1 = (Dictionary)value1; var dict2 = (Dictionary)value2; return CompareDictionaries(dict1, dict2); } else { return object.Equals(value1, value2); } } static bool CompareDictionaries(Dictionary dict1, Dictionary dict2) { if(dict1.Count != dict2.Count) return false; foreach(var kvp1 in dict1) { var key1 = kvp1.Key; object value1 = kvp1.Value; object value2; if(!dict2.TryGetValue(key1, out value2)) return false; if(!ComparePropertyValues(value1, value2)) return false; } return true; } struct EnumerationEntry { public SerializedProperty keyProperty; public SerializedProperty valueProperty; public int index; public EnumerationEntry(SerializedProperty keyProperty, SerializedProperty valueProperty, int index) { this.keyProperty = keyProperty; this.valueProperty = valueProperty; this.index = index; } } static IEnumerable EnumerateEntries(SerializedProperty keyArrayProperty, SerializedProperty valueArrayProperty, int startIndex = 0) { if(keyArrayProperty.arraySize > startIndex) { int index = startIndex; var keyProperty = keyArrayProperty.GetArrayElementAtIndex(startIndex); var valueProperty = valueArrayProperty.GetArrayElementAtIndex(startIndex); var endProperty = keyArrayProperty.GetEndProperty(); do { yield return new EnumerationEntry(keyProperty, valueProperty, index); index++; } while(keyProperty.Next(false) && valueProperty.Next(false) && !SerializedProperty.EqualContents(keyProperty, endProperty)); } } } public class SerializableDictionaryStoragePropertyDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { property.Next(true); EditorGUI.PropertyField(position, property, label, true); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { property.Next(true); return EditorGUI.GetPropertyHeight(property); } } ================================================ FILE: Dependencies/SerializableDictionary/Editor/SerializableDictionaryPropertyDrawer.cs.meta ================================================ fileFormatVersion: 2 guid: 91da51d02ab9ebc459d80d5965d40d19 timeCreated: 1492869349 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary/Editor.meta ================================================ fileFormatVersion: 2 guid: 20029ee1c099f4b47afbac48208879b9 folderAsset: yes DefaultImporter: userData: ================================================ FILE: Dependencies/SerializableDictionary/LICENSE.md ================================================ MIT License Copyright (c) 2017 Mathieu Le Ber Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Dependencies/SerializableDictionary/LICENSE.md.meta ================================================ fileFormatVersion: 2 guid: 2a97e78bf2f61e647b9ea0a65d08182f TextScriptImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary/Runtime/SerializableDictionary.Runtime.asmdef ================================================ { "name": "SerializableDictionary.Runtime" } ================================================ FILE: Dependencies/SerializableDictionary/Runtime/SerializableDictionary.Runtime.asmdef.meta ================================================ fileFormatVersion: 2 guid: 479678a6fc2d434439a70c037334ff05 AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary/Runtime/SerializableDictionary.cs ================================================ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization; using UnityEngine; public abstract class SerializableDictionaryBase : Dictionary, ISerializationCallbackReceiver { [SerializeField] TKey[] m_keys; [SerializeField] TValueStorage[] m_values; public SerializableDictionaryBase() { } public SerializableDictionaryBase(IDictionary dict) : base(dict.Count) { foreach (var kvp in dict) { this[kvp.Key] = kvp.Value; } } protected SerializableDictionaryBase(SerializationInfo info, StreamingContext context) : base(info,context){} protected abstract void SetValue(TValueStorage[] storage, int i, TValue value); protected abstract TValue GetValue(TValueStorage[] storage, int i); public void CopyFrom(IDictionary dict) { this.Clear(); foreach (var kvp in dict) { this[kvp.Key] = kvp.Value; } } public void OnAfterDeserialize() { if(m_keys != null && m_values != null && m_keys.Length == m_values.Length) { this.Clear(); int n = m_keys.Length; for(int i = 0; i < n; ++i) { this[m_keys[i]] = GetValue(m_values, i); } m_keys = null; m_values = null; } } public void OnBeforeSerialize() { int n = this.Count; m_keys = new TKey[n]; m_values = new TValueStorage[n]; int i = 0; foreach(var kvp in this) { m_keys[i] = kvp.Key; SetValue(m_values, i, kvp.Value); ++i; } } } public class SerializableDictionary : SerializableDictionaryBase { public SerializableDictionary() { } public SerializableDictionary(IDictionary dict) : base(dict) { } protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info,context){} protected override TValue GetValue(TValue[] storage, int i) { return storage[i]; } protected override void SetValue(TValue[] storage, int i, TValue value) { storage[i] = value; } } public static class SerializableDictionary { public class Storage { public T data; } } public class SerializableDictionary : SerializableDictionaryBase where TValueStorage : SerializableDictionary.Storage, new() { public SerializableDictionary() { } public SerializableDictionary(IDictionary dict) : base(dict) { } protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info,context){} protected override TValue GetValue(TValueStorage[] storage, int i) { return storage[i].data; } protected override void SetValue(TValueStorage[] storage, int i, TValue value) { storage[i] = new TValueStorage(); storage[i].data = value; } } ================================================ FILE: Dependencies/SerializableDictionary/Runtime/SerializableDictionary.cs.meta ================================================ fileFormatVersion: 2 guid: e7be1c9624387604fba4005ccf7dbd5a timeCreated: 1492868176 licenseType: Store MonoImporter: serializedVersion: 2 defaultReferences: [] executionOrder: 0 icon: {instanceID: 0} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary/Runtime.meta ================================================ fileFormatVersion: 2 guid: 530de5b115dd7534da8f7a363e46ff21 folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies/SerializableDictionary.meta ================================================ fileFormatVersion: 2 guid: fe19274f8c2b0a84792bd6eb2e84f3bd folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Dependencies.meta ================================================ fileFormatVersion: 2 guid: 7347c27e9815d5940be3e3aaab93719d folderAsset: yes DefaultImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Editor/AssetCallbacks/CreateDlogGraph.cs ================================================ using UnityEditor; using UnityEditor.ProjectWindowCallback; using UnityEngine; namespace DialogueGraph { internal class CreateDlogGraph : EndNameEditAction { [MenuItem("Assets/Create/Dialogue Graph/Empty Dialogue Graph", false, 1)] public static void CreateDialogueGraph() { ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance(), $"New Dialogue Graph.{DlogGraphImporter.Extension}", Resources.Load(ResourcesUtility.IconBig), null); } public override void Action(int instanceId, string pathName, string resourceFile) { var dlogGraph = new DlogGraphData(); var dlogObject = CreateInstance(); dlogObject.Initialize(dlogGraph); dlogObject.DlogGraph.AssetGuid = AssetDatabase.GetAssetPath(instanceId); dlogObject.DlogGraph.DialogueGraphVersion = DialogueGraphUtility.LatestVersion; dlogObject.AssetGuid = dlogObject.DlogGraph.AssetGuid; DialogueGraphUtility.CreateFile(pathName, dlogObject, false); AssetDatabase.ImportAsset(pathName); } } } ================================================ FILE: Editor/AssetCallbacks/CreateDlogGraph.cs.meta ================================================ fileFormatVersion: 2 guid: 59cfb2bf5b2642d7b229cd3deef9cb50 timeCreated: 1601287977 ================================================ FILE: Editor/AssetCallbacks.meta ================================================ fileFormatVersion: 2 guid: 2fa84c3ec7fe454fa441b8dcd5ac2265 timeCreated: 1601287955 ================================================ FILE: Editor/DialogueGraph.Editor.asmdef ================================================ { "name": "DialogueGraph.Editor", "rootNamespace": "", "references": [ "GUID:d6f4b79f0a67eb24690aba82c1078929", "GUID:4988cf9794f41d64c884876ab6574b89", "GUID:5debd524d9fe37b44aa7aede833a8eb7", "GUID:479678a6fc2d434439a70c037334ff05" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": true, "precompiledReferences": [ "Newtonsoft.Json.dll" ], "autoReferenced": true, "defineConstraints": [], "versionDefines": [], "noEngineReferences": false } ================================================ FILE: Editor/DialogueGraph.Editor.asmdef.meta ================================================ fileFormatVersion: 2 guid: 88c608744485bf646beed5cc3dd91a6c AssemblyDefinitionImporter: externalObjects: {} userData: assetBundleName: assetBundleVariant: ================================================ FILE: Editor/Extensions/DlogExtensions.cs ================================================ using Newtonsoft.Json; using UnityEngine.UIElements; namespace DialogueGraph { public static class DlogExtensions { public static AbstractProperty Deserialize(this SerializedProperty property) { var type = System.Type.GetType(property.Type); return (AbstractProperty) JsonConvert.DeserializeObject(property.Data, type, new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All}); } public static void InjectCustomStyle(this DlogPort port) { var cap = port.Q("cap"); var width = cap.style.width; width.value = new Length(8, LengthUnit.Pixel); cap.style.width = width; var height = cap.style.height; height.value = new Length(12, LengthUnit.Pixel); cap.style.height = height; // Border color var bLColor = cap.style.borderLeftColor; bLColor.value = port.portColor; cap.style.borderLeftColor = bLColor; var bTColor = cap.style.borderTopColor; bTColor.value = port.portColor; cap.style.borderTopColor = bTColor; var bRColor = cap.style.borderRightColor; bRColor.value = port.portColor; cap.style.borderRightColor = bRColor; var bBColor = cap.style.borderBottomColor; bBColor.value = port.portColor; cap.style.borderBottomColor = bBColor; } } } ================================================ FILE: Editor/Extensions/DlogExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 6c473de560d3477fa93a162cabb53e0e timeCreated: 1603619074 ================================================ FILE: Editor/Extensions/GUILayoutHelper.cs ================================================ using System; using UnityEngine; namespace DialogueGraph { public static class GUILayoutHelper { public static void BeginCenterVertically() { GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); } public static void EndCenterVertically() { GUILayout.FlexibleSpace(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); } public static void CenterVertically(Action drawGUI) { BeginCenterVertically(); drawGUI(); EndCenterVertically(); } } } ================================================ FILE: Editor/Extensions/GUILayoutHelper.cs.meta ================================================ fileFormatVersion: 2 guid: b82632cfd46f4b8ca42700903771073e timeCreated: 1606319893 ================================================ FILE: Editor/Extensions/GraphViewExtensions.cs ================================================ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.UIElements; namespace DialogueGraph { public static class GraphViewExtensions { public static void InsertCopyPasteData(this DlogGraphView graphView, CopyPasteData copyPasteData) { if (copyPasteData == null) return; foreach (var property in copyPasteData.Properties) { var copy = property.Copy(); graphView.DlogGraph.SanitizePropertyName(copy); graphView.DlogGraph.SanitizePropertyReference(copy, property.OverrideReferenceName); graphView.DlogGraph.AddProperty(copy); var dependentNodes = copyPasteData.Nodes.Where(node => node.Type == typeof(PropertyNode).FullName); foreach (var node in dependentNodes) { var root = JObject.Parse(node.NodeData); root["propertyGuid"] = copy.GUID; node.NodeData = root.ToString(Formatting.None); } } var remappedNodes = new List(); var remappedEdges = new List(); graphView.DlogGraph.Paste(copyPasteData, remappedNodes, remappedEdges); // Compute the mean of the copied nodes. var centroid = Vector2.zero; var count = 1; foreach (var node in remappedNodes) { var position = node.DrawState.Position.position; centroid += (position - centroid) / count; ++count; } // Get the center of the current view var viewCenter = graphView.contentViewContainer.WorldToLocal(graphView.layout.center); foreach (var node in remappedNodes) { var drawState = node.DrawState; var positionRect = drawState.Position; var position = positionRect.position; position += viewCenter - centroid; positionRect.position = position; drawState.Position = positionRect; node.DrawState = drawState; } graphView.ClearSelection(); graphView.DlogGraph.QueueSelection(remappedNodes, remappedEdges); } } } ================================================ FILE: Editor/Extensions/GraphViewExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 9170694da96b489daea9c57d451d8470 timeCreated: 1602766163 ================================================ FILE: Editor/Extensions/VisualElementExtensions.cs ================================================ using UnityEngine; using UnityEngine.UIElements; namespace DialogueGraph { public static class VisualElementExtensions { public static void AddStyleSheet(this VisualElement element, string path) { var stylesheet = Resources.Load(path); if(stylesheet == null) Debug.LogWarning($"StyleSheet at path \"{path}\" could not be found"); else element.styleSheets.Add(stylesheet); } } } ================================================ FILE: Editor/Extensions/VisualElementExtensions.cs.meta ================================================ fileFormatVersion: 2 guid: 229e7e4f55474e20ad013144d24a39ae timeCreated: 1601282440 ================================================ FILE: Editor/Extensions.meta ================================================ fileFormatVersion: 2 guid: 2a94fe7d0d1e46e7ac194f7ab65aafb1 timeCreated: 1601282428 ================================================ FILE: Editor/Graph/Attributes/TitleAttribute.cs ================================================ using System; namespace DialogueGraph { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class TitleAttribute : Attribute { public readonly string[] Title; public TitleAttribute(params string[] title) { Title = title; } } } ================================================ FILE: Editor/Graph/Attributes/TitleAttribute.cs.meta ================================================ fileFormatVersion: 2 guid: c6b5cce28add4b3cb603e233a3926bd1 timeCreated: 1601474130 ================================================ FILE: Editor/Graph/Attributes.meta ================================================ fileFormatVersion: 2 guid: 2710773280374843a854a2c722541286 timeCreated: 1601474123 ================================================ FILE: Editor/Graph/Data/CopyPasteData.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace DialogueGraph { [Serializable] public class CopyPasteData : ISerializationCallbackReceiver { [NonSerialized] private HashSet nodes = new HashSet(); [NonSerialized] private HashSet edges = new HashSet(); [NonSerialized] private HashSet properties = new HashSet(); // these are the properties that don't get copied but are required by property nodes that get copied [NonSerialized] private HashSet metaProperties = new HashSet(); [SerializeField] private List serializedNodes = new List(); [SerializeField] private List serializedEdges = new List(); [SerializeField] private List serializedProperties = new List(); [SerializeField] private List serializedMetaProperties = new List(); public IEnumerable Nodes => nodes; public IEnumerable Edges => edges; public IEnumerable SerializedNodes => serializedNodes; public IEnumerable SerializedEdges => serializedEdges; public IEnumerable SerializedProperties => serializedProperties; public IEnumerable SerializedMetaProperties => serializedMetaProperties; public IEnumerable Properties => properties; public IEnumerable MetaProperties => metaProperties; private EditorView editorView; public CopyPasteData(EditorView editorView, IEnumerable nodes, IEnumerable edges, IEnumerable properties, IEnumerable metaProperties) { this.editorView = editorView; foreach (var node in nodes) { AddNode(node); foreach (var edge in GetAllEdgesForNode(node)) { AddEdge(edge); } } foreach (var edge in edges) { AddEdge(edge); } foreach (var property in properties) { AddProperty(property); } foreach (var metaProperty in metaProperties) { AddMetaProperty(metaProperty); } } private void AddNode(SerializedNode node) { nodes.Add(node); } private void AddEdge(SerializedEdge edge) { edges.Add(edge); } private void AddProperty(AbstractProperty property) { properties.Add(property); } private void AddMetaProperty(AbstractProperty property) { metaProperties.Add(property); } public void OnBeforeSerialize() { serializedNodes = new List(); foreach (var node in nodes) { serializedNodes.Add(node); } serializedEdges = new List(); foreach (var edge in edges) { serializedEdges.Add(edge); } serializedProperties = new List(); foreach (var property in properties) { serializedProperties.Add(new SerializedProperty(property)); } serializedMetaProperties = new List(); foreach (var property in metaProperties) { serializedMetaProperties.Add(new SerializedProperty(property)); } } public void OnAfterDeserialize() { nodes = new HashSet(); edges = new HashSet(); properties = new HashSet(); metaProperties = new HashSet(); foreach (var node in serializedNodes) { nodes.Add(node); } foreach (var edge in serializedEdges) { edges.Add(edge); } foreach (var prop in serializedProperties) { properties.Add(prop.Deserialize()); } foreach (var prop in serializedMetaProperties) { metaProperties.Add(prop.Deserialize()); } } private IEnumerable GetAllEdgesForNode(SerializedNode node) { var edges = new List(); foreach (var portConnections in node.GuidPortDictionary.Values.Select(port => port.connections)) { edges.AddRange(portConnections.Select(edge => edge.userData).OfType()); } return edges; } public static CopyPasteData FromJson(string json) { try { return JsonUtility.FromJson(json); } catch { // ignored. just means json was not a CopyPasteData object return null; } } } } ================================================ FILE: Editor/Graph/Data/CopyPasteData.cs.meta ================================================ fileFormatVersion: 2 guid: 59de5bfe57a04708b153166215579951 timeCreated: 1602764627 ================================================ FILE: Editor/Graph/Data/DlogGraphData.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEditor.Experimental.GraphView; using UnityEngine; namespace DialogueGraph { [Serializable] public class DlogGraphData : ISerializationCallbackReceiver { public DlogGraphObject Owner { get; set; } [SerializeField] public string AssetGuid; [SerializeField] public bool IsBlackboardVisible; [SerializeField] public string DialogueGraphVersion; [NonSerialized] private Dictionary nodeDictionary = new Dictionary(); [SerializeField] private List nodes = new List(); [NonSerialized] private List addedNodes = new List(); [NonSerialized] private List removedNodes = new List(); [NonSerialized] private List pastedNodes = new List(); public List Nodes => nodes; public List AddedNodes => addedNodes; public List RemovedNodes => removedNodes; public List PastedNodes => pastedNodes; [SerializeField] private List edges = new List(); [NonSerialized] private List addedEdges = new List(); [NonSerialized] private List removedEdges = new List(); public List Edges => edges; public List AddedEdges => addedEdges; public List RemovedEdges => removedEdges; [NonSerialized] private List properties = new List(); [NonSerialized] private List addedProperties = new List(); [NonSerialized] private List removedProperties = new List(); [NonSerialized] private List movedProperties = new List(); [SerializeField] private List serializedProperties = new List(); public List Properties => properties; public List AddedProperties => addedProperties; public List RemovedProperties => removedProperties; public List MovedProperties => movedProperties; [NonSerialized] private List nodeSelectionQueue = new List(); [NonSerialized] private List edgeSelectionQueue = new List(); public List NodeSelectionQueue => nodeSelectionQueue; public List EdgeSelectionQueue => edgeSelectionQueue; public void OnBeforeSerialize() { if (Owner != null) IsBlackboardVisible = Owner.IsBlackboardVisible; serializedProperties.Clear(); foreach (var property in properties) { serializedProperties.Add(new SerializedProperty(property)); } } public void OnAfterDeserialize() { nodes.ForEach(node => nodeDictionary.Add(node.GUID, node)); serializedProperties.ForEach(prop => AddProperty(prop.Deserialize())); } public void ClearChanges() { addedNodes.Clear(); removedNodes.Clear(); addedEdges.Clear(); removedEdges.Clear(); addedProperties.Clear(); removedProperties.Clear(); movedProperties.Clear(); nodeSelectionQueue.Clear(); edgeSelectionQueue.Clear(); } public void ReplaceWith(DlogGraphData otherGraphData) { // Remove everything var removedNodesGuid = new List(); removedNodesGuid.AddRange(nodes.Select(node => node.GUID)); foreach (var node in removedNodesGuid) { RemoveNode(nodeDictionary[node]); } var removedProperties = new List(properties); foreach (var prop in removedProperties) RemoveProperty(prop); // Add back everything foreach (var node in otherGraphData.nodes) { AddNode(node); } foreach (var edge in otherGraphData.edges) { AddEdge(edge); } foreach (var property in otherGraphData.properties) { AddProperty(property); } } public void AddNode(SerializedNode node) { nodeDictionary.Add(node.GUID, node); nodes.Add(node); addedNodes.Add(node); } public void RemoveNode(SerializedNode node) { if (!nodeDictionary.ContainsKey(node.GUID)) throw new InvalidOperationException($"Cannot remove node ({node.GUID}) because it doesn't exist."); nodes.Remove(node); nodeDictionary.Remove(node.GUID); removedNodes.Add(node); edges.Where(edge => edge.Input == node.GUID || edge.Output == node.GUID).ToList().ForEach(RemoveEdge); } public bool HasEdge(Edge edge) { var serializedEdge = new SerializedEdge { Input = edge.input.node.viewDataKey, Output = edge.output.node.viewDataKey, InputPort = edge.input.viewDataKey, OutputPort = edge.output.viewDataKey }; return Edges.Any(edge1 => edge1.Input == serializedEdge.Input && edge1.Output == serializedEdge.Output && edge1.InputPort == serializedEdge.InputPort && edge1.OutputPort == serializedEdge.OutputPort); } public void AddEdge(Edge edge) { var serializedEdge = new SerializedEdge { Input = edge.input.node.viewDataKey, Output = edge.output.node.viewDataKey, InputPort = edge.input.viewDataKey, OutputPort = edge.output.viewDataKey, InputCapacity = edge.input.capacity, OutputCapacity = edge.output.capacity }; AddEdge(serializedEdge); } public void AddEdge(SerializedEdge edge) { if (edge.InputCapacity == Port.Capacity.Single) { // Remove all edges with the same port var temp = new List(); temp.AddRange(edges.Where(edge1 => edge1.InputPort == edge.InputPort)); temp.ForEach(RemoveEdge); } if (edge.OutputCapacity == Port.Capacity.Single) { // Remove all edges with the same port var temp = new List(); temp.AddRange(edges.Where(edge1 => edge1.OutputPort == edge.OutputPort)); temp.ForEach(RemoveEdge); } edges.Add(edge); addedEdges.Add(edge); } public void RemoveEdge(SerializedEdge edge) { edges.Remove(edge); removedEdges.Add(edge); } public void AddProperty(AbstractProperty property) { if (property == null) return; if (properties.Contains(property)) return; properties.Add(property); addedProperties.Add(property); } public void RemoveProperty(AbstractProperty property) { var propertyNodes = nodes.FindAll(node => node.Node is PropertyNode propertyNode && propertyNode.PropertyGuid == property.GUID); foreach (var node in propertyNodes) RemoveNode(node); if (properties.Remove(property)) { removedProperties.Add(property); addedProperties.Remove(property); movedProperties.Remove(property); } } public void MoveProperty(AbstractProperty property, int newIndex) { if (newIndex > properties.Count || newIndex < 0) throw new ArgumentException("New index is not within properties list."); var currentIndex = properties.IndexOf(property); if (currentIndex == -1) throw new ArgumentException("Property is not in graph."); if (newIndex == currentIndex) { Debug.Log($"New index is the same as current index {newIndex} == {currentIndex}"); return; } properties.RemoveAt(currentIndex); if (newIndex > currentIndex) newIndex--; var isLast = newIndex == properties.Count; if (isLast) { Debug.Log($"New index is the last index new:{newIndex} current:{currentIndex}"); properties.Add(property); } else { Debug.Log($"new:{newIndex} current:{currentIndex}"); properties.Insert(newIndex, property); } if (!movedProperties.Contains(property)) movedProperties.Add(property); } public void RemoveElements(List nodes, List edges) { foreach (var edge in edges) { RemoveEdge(edge); } foreach (var node in nodes) { RemoveNode(node); } } public void QueueSelection(List nodes, List edges) { nodeSelectionQueue.AddRange(nodes); edgeSelectionQueue.AddRange(edges); } public void SanitizePropertyName(AbstractProperty property) { property.DisplayName = property.DisplayName.Trim(); property.DisplayName = DialogueGraphUtility.SanitizeName(properties.Where(prop => prop.GUID != property.GUID).Select(prop => prop.DisplayName), "{0} ({1})", property.DisplayName); } public void SanitizePropertyReference(AbstractProperty property, string newReferenceName) { if (string.IsNullOrEmpty(newReferenceName)) return; var name = newReferenceName.Trim(); if (string.IsNullOrEmpty(name)) return; property.OverrideReferenceName = DialogueGraphUtility.SanitizeName(properties.Where(prop => prop.GUID != property.GUID).Select(prop => prop.ReferenceName), "{0} ({1})", name); } public void Paste(CopyPasteData copyPasteData, List remappedNodes, List remappedEdges) { var nodeGuidMap = new Dictionary(); var portGuidMap = new Dictionary(); foreach (var node in copyPasteData.Nodes) { var oldGuid = node.GUID; var newGuid = Guid.NewGuid().ToString(); node.GUID = newGuid; nodeGuidMap[oldGuid] = newGuid; for (var i = 0; i < node.PortData.Count; i++) { var newPortGuid = Guid.NewGuid().ToString(); var oldPortGuid = node.PortData[i]; portGuidMap[oldPortGuid] = newPortGuid; node.PortData[i] = newPortGuid; } // Ugly magic to change dynamic port guid data if (node.Type == typeof(SelfNode).FullName) { var data = JObject.Parse(node.NodeData); var lines = JsonConvert.DeserializeObject>(data.Value("lines")); foreach (var currLine in lines) { currLine.PortGuidA = portGuidMap[currLine.PortGuidA]; currLine.PortGuidB = portGuidMap[currLine.PortGuidB]; } data["lines"] = new JValue(JsonConvert.SerializeObject(lines)); node.NodeData = data.ToString(Formatting.None); } else if (node.Type == typeof(NpcNode).FullName) { var data = JObject.Parse(node.NodeData); var lines = JsonConvert.DeserializeObject>(data.Value("lines")); foreach (var currLine in lines) { currLine.PortGuidA = portGuidMap[currLine.PortGuidA]; currLine.PortGuidB = portGuidMap[currLine.PortGuidB]; currLine.PortGuidC = portGuidMap[currLine.PortGuidC]; } data["lines"] = new JValue(JsonConvert.SerializeObject(lines)); node.NodeData = data.ToString(Formatting.None); } // offset the pasted node slightly so it's not on top of the original one var drawState = node.DrawState; var position = drawState.Position; position.x += 30; position.y += 30; drawState.Position = position; node.DrawState = drawState; remappedNodes.Add(node); AddNode(node); // add the node to the pasted node list pastedNodes.Add(node); } foreach (var edge in copyPasteData.Edges) { if ((nodeGuidMap.ContainsKey(edge.Input) && nodeGuidMap.ContainsKey(edge.Output)) && (portGuidMap.ContainsKey(edge.InputPort) && portGuidMap.ContainsKey(edge.OutputPort))) { var remappedOutputGuid = nodeGuidMap.ContainsKey(edge.Output) ? nodeGuidMap[edge.Output] : edge.Output; var remappedInputGuid = nodeGuidMap.ContainsKey(edge.Input) ? nodeGuidMap[edge.Input] : edge.Input; var remappedOutputPortGuid = portGuidMap.ContainsKey(edge.OutputPort) ? portGuidMap[edge.OutputPort] : edge.OutputPort; var remappedInputPortGuid = portGuidMap.ContainsKey(edge.InputPort) ? portGuidMap[edge.InputPort] : edge.InputPort; var remappedEdge = new SerializedEdge { Input = remappedInputGuid, Output = remappedOutputGuid, InputPort = remappedInputPortGuid, OutputPort = remappedOutputPortGuid, InputCapacity = edge.InputCapacity, OutputCapacity = edge.OutputCapacity }; remappedEdges.Add(remappedEdge); AddEdge(remappedEdge); } } } } } ================================================ FILE: Editor/Graph/Data/DlogGraphData.cs.meta ================================================ fileFormatVersion: 2 guid: c191dd86e9a94d78baaeb54ed76b3022 timeCreated: 1601289631 ================================================ FILE: Editor/Graph/Data/DlogGraphObject.cs ================================================ using System; using UnityEditor; using UnityEngine; namespace DialogueGraph { public class DlogGraphObject : ScriptableObject, ISerializationCallbackReceiver { [NonSerialized] private DlogGraphData dlogGraph; [NonSerialized] private int objectVersion; [SerializeField] public string AssetGuid; [SerializeField] public bool IsBlackboardVisible; [SerializeField] private string serializedGraph; [SerializeField] private int fileVersion; [SerializeField] private bool isDirty; public DlogGraphData DlogGraph { get => dlogGraph; set { dlogGraph = value; if (dlogGraph != null) dlogGraph.Owner = this; } } public void Initialize(DlogGraphData dlogData) { DlogGraph = dlogData; IsBlackboardVisible = DlogGraph.IsBlackboardVisible; } public bool IsDirty { get => isDirty; set => isDirty = value; } public bool WasUndoRedoPerformed => objectVersion != fileVersion; public void RegisterCompleteObjectUndo(string name) { Undo.RegisterCompleteObjectUndo(this, name); fileVersion++; objectVersion++; isDirty = true; } public void OnBeforeSerialize() { if(dlogGraph == null) return; serializedGraph = JsonUtility.ToJson(dlogGraph, true); AssetGuid = dlogGraph.AssetGuid; } public void OnAfterDeserialize() { if(DlogGraph != null) return; DlogGraph = Deserialize(); } public void HandleUndoRedo() { if (!WasUndoRedoPerformed) { Debug.LogError("Trying to handle undo/redo when undo/redo was not performed", this); return; } var deserialized = Deserialize(); dlogGraph.ReplaceWith(deserialized); // Undo.PerformUndo(); } private DlogGraphData Deserialize() { var deserialized = JsonUtility.FromJson(serializedGraph); deserialized.AssetGuid = AssetGuid; objectVersion = fileVersion; serializedGraph = ""; return deserialized; } public void RecalculateAssetGuid(string assetPath) { AssetGuid = AssetDatabase.AssetPathToGUID(assetPath); dlogGraph.AssetGuid = AssetGuid; } } } ================================================ FILE: Editor/Graph/Data/DlogGraphObject.cs.meta ================================================ fileFormatVersion: 2 guid: 45a52db35d93407fb259c4996ec53fa6 timeCreated: 1601289640 ================================================ FILE: Editor/Graph/Data/NodeDrawState.cs ================================================ using System; using UnityEngine; namespace DialogueGraph { [Serializable] public struct NodeDrawState { [SerializeField] public Rect Position; [SerializeField] public bool Expanded; } } ================================================ FILE: Editor/Graph/Data/NodeDrawState.cs.meta ================================================ fileFormatVersion: 2 guid: 76290e77b5a74b6ba5d52be0d2aaa0ef timeCreated: 1601551907 ================================================ FILE: Editor/Graph/Data/Properties/AbstractProperty.cs ================================================ using System; using DialogueGraph.Runtime; using UnityEngine; namespace DialogueGraph { [Serializable] public abstract class AbstractProperty { [SerializeField] public string GUID = Guid.NewGuid().ToString(); [SerializeField] public PropertyType Type; [SerializeField] private string name; [SerializeField] private string defaultReferenceName; [SerializeField] private string overrideReferenceName; [SerializeField] private bool hidden; public string DisplayName { get { if (string.IsNullOrEmpty(name)) return $"{Type}_{ShortGuid}"; return name; } set => name = value; } public string ReferenceName { get { if (string.IsNullOrEmpty(OverrideReferenceName)) { if (string.IsNullOrEmpty(defaultReferenceName)) defaultReferenceName = GetDefaultReferenceName(); return defaultReferenceName; } return OverrideReferenceName; } } public string OverrideReferenceName { get => overrideReferenceName; set => overrideReferenceName = value; } public bool Hidden { get => hidden; set => hidden = value; } public virtual string GetDefaultReferenceName() { return $"{Type}_{ShortGuid}"; } public string ShortGuid { get { if (string.IsNullOrEmpty(GUID)) GUID = Guid.NewGuid().ToString(); if (Guid.TryParse(GUID, out var parsedGuid)) return $"{Convert.ToBase64String(parsedGuid.ToByteArray()).GetHashCode():X}"; return $"{Convert.ToBase64String(Guid.NewGuid().ToByteArray()).GetHashCode():X}"; } } public abstract AbstractProperty Copy(); } [Serializable] public abstract class AbstractProperty : AbstractProperty { private T value; public T Value { get => value; set => this.value = value; } } } ================================================ FILE: Editor/Graph/Data/Properties/AbstractProperty.cs.meta ================================================ fileFormatVersion: 2 guid: 8b7821e2c03c442f8979d30247900abe timeCreated: 1602590130 ================================================ FILE: Editor/Graph/Data/Properties/ActorProperty.cs ================================================ using System; using DialogueGraph.Runtime; using UnityEngine; namespace DialogueGraph { [Serializable] public class ActorProperty : AbstractProperty { public ActorProperty() { DisplayName = "Actor"; Type = PropertyType.Actor; } public override AbstractProperty Copy() { return new ActorProperty { DisplayName = DisplayName, Hidden = Hidden }; } } } ================================================ FILE: Editor/Graph/Data/Properties/ActorProperty.cs.meta ================================================ fileFormatVersion: 2 guid: b1714ccfa2d94454bad768ada07829b1 timeCreated: 1602591421 ================================================ FILE: Editor/Graph/Data/Properties/CheckProperty.cs ================================================ using System; using DialogueGraph.Runtime; namespace DialogueGraph { [Serializable] public class CheckProperty : AbstractProperty { public CheckProperty() { DisplayName = "Check"; Type = PropertyType.Check; } public override AbstractProperty Copy() { return new CheckProperty { DisplayName = DisplayName, Hidden = Hidden }; } } } ================================================ FILE: Editor/Graph/Data/Properties/CheckProperty.cs.meta ================================================ fileFormatVersion: 2 guid: 791df7817718417b8d85ff456275f787 timeCreated: 1602591348 ================================================ FILE: Editor/Graph/Data/Properties/TriggerProperty.cs ================================================ using System; using DialogueGraph.Runtime; namespace DialogueGraph { [Serializable] public class TriggerProperty : AbstractProperty { public TriggerProperty() { DisplayName = "Trigger"; Type = PropertyType.Trigger; } public override AbstractProperty Copy() { return new TriggerProperty { DisplayName = DisplayName, Hidden = Hidden }; } } } ================================================ FILE: Editor/Graph/Data/Properties/TriggerProperty.cs.meta ================================================ fileFormatVersion: 2 guid: b4055b2efff2408cbc7af168eedbc563 timeCreated: 1602590953 ================================================ FILE: Editor/Graph/Data/Properties.meta ================================================ fileFormatVersion: 2 guid: f28d6edcc2e74cfc9d314ba343872167 timeCreated: 1602590819 ================================================ FILE: Editor/Graph/Data/SerializedEdge.cs ================================================ using System; using UnityEditor.Experimental.GraphView; using UnityEngine; using Edge = UnityEditor.Experimental.GraphView.Edge; namespace DialogueGraph { [Serializable] public class SerializedEdge { [SerializeField] public string Input; [SerializeField] public string Output; [SerializeField] public string InputPort; [SerializeField] public string OutputPort; public Port.Capacity InputCapacity; public Port.Capacity OutputCapacity; public Edge Edge; public EditorView EditorView; public void BuildEdge(EditorView editorView) { EditorView = editorView; var inputNode = editorView.GraphView.nodes.ToList().Find(node => node.viewDataKey == Input) as AbstractNode; var outputNode = editorView.GraphView.nodes.ToList().Find(node => node.viewDataKey == Output) as AbstractNode; var inputPort = inputNode.Owner.GuidPortDictionary[InputPort]; var outputPort = outputNode.Owner.GuidPortDictionary[OutputPort]; Edge = inputPort.ConnectTo(outputPort); Edge.userData = this; } } } ================================================ FILE: Editor/Graph/Data/SerializedEdge.cs.meta ================================================ fileFormatVersion: 2 guid: 647548daa8934a929f8e14371c0705df timeCreated: 1601479470 ================================================ FILE: Editor/Graph/Data/SerializedNode.cs ================================================ using System; using System.Collections.Generic; using System.IO; using UnityEditor.Experimental.GraphView; using UnityEngine; namespace DialogueGraph { [Serializable] public class SerializedNode : ISerializationCallbackReceiver { [SerializeField] public string GUID; [SerializeField] public string Type; [SerializeField] public NodeDrawState DrawState; [SerializeField] public string NodeData; [SerializeField] public List PortData; [NonSerialized] public Dictionary GuidPortDictionary; public EditorView EditorView; public AbstractNode Node; public SerializedNode(Type type, Rect position) { Type = type.FullName; DrawState.Position = position; DrawState.Expanded = true; GUID = Guid.NewGuid().ToString(); } public void BuildNode(EditorView editorView, EdgeConnectorListener edgeConnectorListener, bool buildPortData = true) { EditorView = editorView; Node = (AbstractNode) Activator.CreateInstance(System.Type.GetType(Type)); Node.InitializeNode(edgeConnectorListener); Node.GUID = GUID; Node.viewDataKey = GUID; Node.Owner = this; Node.SetExpandedWithoutNotify(DrawState.Expanded); Node.SetPosition(DrawState.Position); if (!string.IsNullOrEmpty(NodeData)) Node.SetNodeData(NodeData); Node.Refresh(); if (buildPortData) BuildPortData(); } public void BuildPortData() { if ((Node.Ports == null || Node.Ports.Count == 0) && (PortData == null || PortData.Count == 0)) { return; } if ((PortData == null || PortData.Count == 0) && Node.Ports.Count != 0 || (PortData != null && PortData.Count != Node.Ports.Count && Node.Ports.Count != 0)) { // GET PortData = new List(); foreach (var port in Node.Ports) { PortData.Add(port.viewDataKey); } } else { // SET if (PortData == null) throw new InvalidDataException("Serialized port data somehow ended up as null when it was not supposed to."); for (var i = 0; i < PortData.Count; i++) { Node.Ports[i].viewDataKey = PortData[i]; } } // Build dictionary GuidPortDictionary = new Dictionary(); foreach (var port in Node.Ports) { GuidPortDictionary.Add(port.viewDataKey, port); } } public void OnBeforeSerialize() { if (Node == null) return; Node.OnNodeSerialized(); NodeData = Node.GetNodeData(); } public void OnAfterDeserialize() { if (Node == null) return; Node.OnNodeDeserialized(); if (!string.IsNullOrEmpty(NodeData)) Node.SetNodeData(NodeData); } } } ================================================ FILE: Editor/Graph/Data/SerializedNode.cs.meta ================================================ fileFormatVersion: 2 guid: 7a13f7ce51ca435792839c6342944c7d timeCreated: 1601479420 ================================================ FILE: Editor/Graph/Data/SerializedProperty.cs ================================================ using System; using Newtonsoft.Json; namespace DialogueGraph { [Serializable] public class SerializedProperty { public string Type; public string Data; public SerializedProperty(AbstractProperty property) { Data = JsonConvert.SerializeObject(property, Formatting.None, new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All}); Type = property.GetType().FullName; } } } ================================================ FILE: Editor/Graph/Data/SerializedProperty.cs.meta ================================================ fileFormatVersion: 2 guid: 851b6a27fb244793a696f96b78ccf017 timeCreated: 1602600670 ================================================ FILE: Editor/Graph/Data/VersionMismatchObject.cs ================================================ using UnityEngine; namespace DialogueGraph { internal class VersionMismatchObject : ScriptableObject { } } ================================================ FILE: Editor/Graph/Data/VersionMismatchObject.cs.meta ================================================ fileFormatVersion: 2 guid: 15c4241bdbc14e7e9ac2eabe65b9b4b7 timeCreated: 1649591459 ================================================ FILE: Editor/Graph/Data.meta ================================================ fileFormatVersion: 2 guid: dd017a28da8740f881573ba039014b54 timeCreated: 1601480300 ================================================ FILE: Editor/Graph/Nodes/AbstractNode.cs ================================================ using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.UIElements; namespace DialogueGraph { public abstract class AbstractNode : Node { public SerializedNode Owner { get; set; } public string GUID; public readonly List Ports = new List(); protected EdgeConnectorListener EdgeConnectorListener; public override bool expanded { get => base.expanded; set { Owner.EditorView.DlogObject.RegisterCompleteObjectUndo("Expanded state changed"); base.expanded = value; Owner.DrawState.Expanded = value; } } // ReSharper disable once InconsistentNaming, UnusedAutoPropertyAccessor.Local [Obsolete("Use AddPort instead of manually adding ports to the container. Only use this if you're adding custom items to the container.", false)] protected new VisualElement inputContainer => base.inputContainer; // ReSharper disable once InconsistentNaming, UnusedAutoPropertyAccessor.Local [Obsolete("Use AddPort instead of manually adding ports to the container. Only use this if you're adding custom items to the container.", false)] protected new VisualElement outputContainer => base.outputContainer; protected void AddPort(Port port, bool alsoAddToHierarchy = true) { Ports.Add(port); if(!alsoAddToHierarchy) return; var isInput = port.direction == Direction.Input; if (isInput) { base.inputContainer.Add(port); } else { base.outputContainer.Add(port); } } public virtual void InitializeNode(EdgeConnectorListener edgeConnectorListener) { EdgeConnectorListener = edgeConnectorListener; } protected void Initialize(string nodeTitle, Rect nodePosition) { base.title = nodeTitle; base.SetPosition(nodePosition); GUID = Guid.NewGuid().ToString(); viewDataKey = GUID; this.AddStyleSheet("Styles/Node/Node"); InjectCustomStyle(); } protected virtual void InjectCustomStyle() { var border = this.Q("node-border"); var overflowStyle = border.style.overflow; overflowStyle.value = Overflow.Visible; border.style.overflow = overflowStyle; var selectionBorder = this.Q("selection-border"); selectionBorder.SendToBack(); } public void Refresh() { RefreshPorts(); RefreshExpandedState(); } public void SetExpandedWithoutNotify(bool value) { base.expanded = value; } public virtual void SetNodeData(string jsonData) { } public virtual string GetNodeData() { var root = new JObject(); return root.ToString(Formatting.None); } public virtual void OnNodeSerialized() { } public virtual void OnNodeDeserialized() { } } } ================================================ FILE: Editor/Graph/Nodes/AbstractNode.cs.meta ================================================ fileFormatVersion: 2 guid: eb86560c1bb04cc997a78be15a95ac6e timeCreated: 1601474268 ================================================ FILE: Editor/Graph/Nodes/Boolean/BinaryBooleanNode.cs ================================================ using UnityEditor.Experimental.GraphView; using UnityEngine.UIElements; namespace DialogueGraph { public abstract class BinaryBooleanNode : AbstractNode { protected abstract string Title { get; } protected abstract BooleanOperation Operation { get; } public override void InitializeNode(EdgeConnectorListener edgeConnectorListener) { base.InitializeNode(edgeConnectorListener); Initialize(Title, EditorView.DefaultNodePosition); this.AddStyleSheet("Styles/Node/BooleanNode"); AddToClassList(Operation.ToString()); DlogPort inA = DlogPort.Create("INA", Orientation.Horizontal, Direction.Input, Port.Capacity.Single, PortType.Boolean, true, edgeConnectorListener, true); DlogPort inB = DlogPort.Create("INB", Orientation.Horizontal, Direction.Input, Port.Capacity.Single, PortType.Boolean, true, edgeConnectorListener, true); DlogPort @out = DlogPort.Create("OUT", Orientation.Horizontal, Direction.Output, Port.Capacity.Single, PortType.Boolean, true, edgeConnectorListener, true); AddPort(inA, false); AddPort(inB, false); AddPort(@out, false); VisualElement booleanMain = UIElementsFactory.VisualElement("boolean-main", null); VisualElement booleanInput = UIElementsFactory.VisualElement("boolean-input", new[] {"boolean-column"}); VisualElement booleanOutput = UIElementsFactory.VisualElement("boolean-output", new[] {"boolean-column"}); booleanMain.Add(booleanInput); booleanMain.Add(UIElementsFactory.TextElement