diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..1751681
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,21 @@
+# Changelog
+
+All notable changes to this package will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [1.0.0] - 2020-07-15
+
+### Added
+
+- Blackboard and other core functionality.
+- Blackboard serialization.
+- Unity components support.
+- Unity editor support.
+- Tests.
+
+[unreleased]: https://github.com/ZorPastaman/Simple-Blackboard/compare/v1.0.0...HEAD
+[1.0.0]: https://github.com/ZorPastaman/Simple-Blackboard/releases/tag/v1.0.0
diff --git a/CHANGELOG.md.meta b/CHANGELOG.md.meta
new file mode 100644
index 0000000..4b50549
--- /dev/null
+++ b/CHANGELOG.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 18c5568f872809246a8b3b4b4b0dba17
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor.meta b/Editor.meta
new file mode 100644
index 0000000..ca91afe
--- /dev/null
+++ b/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f7118688bb48e744a93987fe1692851d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/AddPopups.meta b/Editor/AddPopups.meta
new file mode 100644
index 0000000..bb9af28
--- /dev/null
+++ b/Editor/AddPopups.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d9a9c856b4a13b34ca820c2e86e1230e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/AddPopups/AddPopup.cs b/Editor/AddPopups/AddPopup.cs
new file mode 100644
index 0000000..a61eb1e
--- /dev/null
+++ b/Editor/AddPopups/AddPopup.cs
@@ -0,0 +1,76 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using UnityEditor;
+using UnityEngine;
+using Zor.SimpleBlackboard.Core;
+
+namespace Zor.SimpleBlackboard.BlackboardTableEditors
+{
+ ///
+ /// Popup used for adding new properties to in the editor.
+ ///
+ internal sealed class AddPopup : EditorWindow
+ {
+ private GUIContent m_closeButtonIcon;
+ private GUILayoutOption[] m_closeButtonOptions;
+
+ private Blackboard m_blackboard;
+ private string m_key;
+ private IAddPopupValue m_addPopupValue;
+
+ private Vector2 m_scrollPos;
+
+ ///
+ /// Sets necessary parameters to . Call this before first .
+ ///
+ /// New property is added to this.
+ /// Initial key. It can be changed in .
+ /// Value wrapper.
+ /// Position of the popup in the editor space.
+ public void Setup(Blackboard blackboard, string key, IAddPopupValue addPopupValue, Vector2 popupPosition)
+ {
+ m_blackboard = blackboard;
+ m_key = key;
+ m_addPopupValue = addPopupValue;
+ var size = new Vector2(450f, EditorGUIUtility.singleLineHeight * 8f
+ + EditorGUIUtility.standardVerticalSpacing * 6f);
+
+ ShowAsDropDown(new Rect(popupPosition, size), size);
+ }
+
+ private void OnEnable()
+ {
+ m_closeButtonIcon = EditorGUIUtility.IconContent("LookDevClose");
+ m_closeButtonOptions = new[] { GUILayout.Width(32f) };
+ }
+
+ private void OnGUI()
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ EditorGUILayout.LabelField(m_addPopupValue.valueType.Name, EditorStyles.toolbarButton);
+
+ if (GUILayout.Button(m_closeButtonIcon, EditorStyles.toolbarButton, m_closeButtonOptions))
+ {
+ Close();
+ return;
+ }
+
+ EditorGUILayout.EndHorizontal();
+
+ m_key = EditorGUILayout.TextField("Key", m_key);
+
+ m_scrollPos = EditorGUILayout.BeginScrollView(m_scrollPos);
+
+ m_addPopupValue.DrawValue("Value");
+
+ EditorGUILayout.EndScrollView();
+
+ if (GUILayout.Button("OK"))
+ {
+ m_addPopupValue.Set(m_key, m_blackboard);
+ Close();
+ }
+ }
+ }
+}
diff --git a/Editor/AddPopups/AddPopup.cs.meta b/Editor/AddPopups/AddPopup.cs.meta
new file mode 100644
index 0000000..a5b3436
--- /dev/null
+++ b/Editor/AddPopups/AddPopup.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5389a4a3485cf35459bf7efcee410ce9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/AddPopups/AddPopupValue.cs b/Editor/AddPopups/AddPopupValue.cs
new file mode 100644
index 0000000..b4367a0
--- /dev/null
+++ b/Editor/AddPopups/AddPopupValue.cs
@@ -0,0 +1,42 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using System;
+using Zor.SimpleBlackboard.BlackboardValueViews;
+using Zor.SimpleBlackboard.Core;
+
+namespace Zor.SimpleBlackboard.BlackboardTableEditors
+{
+ ///
+ /// Value wrapper used in .
+ ///
+ /// Value type.
+ internal sealed class AddPopupValue : IAddPopupValue
+ {
+ private readonly BlackboardValueView m_valueView;
+ private T m_value;
+
+ ///
+ /// Creates a wrapper over .
+ ///
+ /// Value view of used in this wrapper.
+ public AddPopupValue(BlackboardValueView valueView)
+ {
+ m_valueView = valueView;
+ }
+
+ ///
+ public Type valueType => typeof(T);
+
+ ///
+ public void DrawValue(string label)
+ {
+ m_value = m_valueView.DrawValue(label, m_value);
+ }
+
+ ///
+ public void Set(string key, Blackboard blackboard)
+ {
+ blackboard.SetObjectValue(typeof(T), new BlackboardPropertyName(key), m_value);
+ }
+ }
+}
diff --git a/Editor/AddPopups/AddPopupValue.cs.meta b/Editor/AddPopups/AddPopupValue.cs.meta
new file mode 100644
index 0000000..b42f669
--- /dev/null
+++ b/Editor/AddPopups/AddPopupValue.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1454c656d6e67ac4db0b903e3ec8fbaa
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/AddPopups/IAddPopupValue.cs b/Editor/AddPopups/IAddPopupValue.cs
new file mode 100644
index 0000000..40a6663
--- /dev/null
+++ b/Editor/AddPopups/IAddPopupValue.cs
@@ -0,0 +1,31 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using System;
+using Zor.SimpleBlackboard.Core;
+
+namespace Zor.SimpleBlackboard.BlackboardTableEditors
+{
+ ///
+ /// Interface for a value wrapper used in .
+ ///
+ internal interface IAddPopupValue
+ {
+ ///
+ /// Type of the value.
+ ///
+ Type valueType { get; }
+
+ ///
+ /// Draws an editor for the value.
+ ///
+ /// Property label.
+ void DrawValue(string label);
+
+ ///
+ /// Sets the current value into using as a property name.
+ ///
+ /// Property name.
+ /// Sets current value into this.
+ void Set(string key, Blackboard blackboard);
+ }
+}
diff --git a/Editor/AddPopups/IAddPopupValue.cs.meta b/Editor/AddPopups/IAddPopupValue.cs.meta
new file mode 100644
index 0000000..de77a92
--- /dev/null
+++ b/Editor/AddPopups/IAddPopupValue.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: daedc2dcbe7296f4691f2286c5bd1b9c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/CustomEditors.meta b/Editor/CustomEditors.meta
new file mode 100644
index 0000000..ee24b02
--- /dev/null
+++ b/Editor/CustomEditors.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dfcf19b34948e3b40beb41d1d3a8ea81
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/CustomEditors/BlackboardContainerComponentCustomEditor.cs b/Editor/CustomEditors/BlackboardContainerComponentCustomEditor.cs
new file mode 100644
index 0000000..0bcd465
--- /dev/null
+++ b/Editor/CustomEditors/BlackboardContainerComponentCustomEditor.cs
@@ -0,0 +1,34 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using UnityEditor;
+using Zor.SimpleBlackboard.EditorTools;
+
+namespace Zor.SimpleBlackboard.Components
+{
+ [CustomEditor(typeof(BlackboardContainer))]
+ public sealed class BlackboardContainerComponentCustomEditor : Editor
+ {
+ private bool m_constantRepaint;
+
+ public override void OnInspectorGUI()
+ {
+ base.OnInspectorGUI();
+
+ if (!EditorApplication.isPlaying)
+ {
+ return;
+ }
+
+ EditorGUILayout.Separator();
+ m_constantRepaint = EditorGUILayout.Toggle("Require Constant Repaint", m_constantRepaint);
+
+ var blackboardContainer = (BlackboardContainer)target;
+ BlackboardEditor.DrawBlackboard(blackboardContainer.blackboard);
+ }
+
+ public override bool RequiresConstantRepaint()
+ {
+ return m_constantRepaint;
+ }
+ }
+}
diff --git a/Editor/CustomEditors/BlackboardContainerComponentCustomEditor.cs.meta b/Editor/CustomEditors/BlackboardContainerComponentCustomEditor.cs.meta
new file mode 100644
index 0000000..bcea19f
--- /dev/null
+++ b/Editor/CustomEditors/BlackboardContainerComponentCustomEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aaeb70078cf571f4ab0892029cb1c263
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/CustomEditors/BlackboardPropertyReferenceEditor.cs b/Editor/CustomEditors/BlackboardPropertyReferenceEditor.cs
new file mode 100644
index 0000000..4d54ef1
--- /dev/null
+++ b/Editor/CustomEditors/BlackboardPropertyReferenceEditor.cs
@@ -0,0 +1,147 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using System;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+using Zor.SimpleBlackboard.Serialization;
+using Object = UnityEngine.Object;
+
+namespace Zor.SimpleBlackboard.Components
+{
+ [CustomPropertyDrawer(typeof(BlackboardPropertyReference))]
+ public sealed class BlackboardPropertyReferenceEditor : PropertyDrawer
+ {
+private const string BlackboardContainerPropertyName = "blackboardContainer";
+ private const string PropertyNamePropertyName = "propertyName";
+
+ private const string SerializedContainersPropertyName = "m_SerializedContainers";
+
+ private static readonly GenericMenu.MenuFunction2 s_onMenuItem = OnMenuItem;
+
+ private static readonly List<(string, Type)> s_propertyKeysCache = new List<(string, Type)>();
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
+ {
+ float height = EditorGUI.GetPropertyHeight(property, false);
+
+ if (property.isExpanded)
+ {
+ SerializedProperty blackboardContainerProperty =
+ property.FindPropertyRelative(BlackboardContainerPropertyName);
+ SerializedProperty propertyNameProperty = property.FindPropertyRelative(PropertyNamePropertyName);
+
+ height += EditorGUI.GetPropertyHeight(blackboardContainerProperty)
+ + EditorGUI.GetPropertyHeight(propertyNameProperty) + 2f * EditorGUIUtility.standardVerticalSpacing;
+ }
+
+ return height;
+ }
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ position.height = EditorGUI.GetPropertyHeight(property, false);
+ EditorGUI.PropertyField(position, property, false);
+
+ if (!property.isExpanded)
+ {
+ return;
+ }
+
+ ++EditorGUI.indentLevel;
+
+ SerializedProperty blackboardContainerProperty =
+ property.FindPropertyRelative(BlackboardContainerPropertyName);
+ SerializedProperty propertyNameProperty = property.FindPropertyRelative(PropertyNamePropertyName);
+ Object blackboardContainer = blackboardContainerProperty.objectReferenceValue;
+ SerializedProperty serializedContainersProperty = blackboardContainer == null
+ ? null
+ : new SerializedObject(blackboardContainer).FindProperty(SerializedContainersPropertyName);
+
+ position.y += position.height + EditorGUIUtility.standardVerticalSpacing;
+ position.height = EditorGUI.GetPropertyHeight(blackboardContainerProperty);
+ EditorGUI.PropertyField(position, blackboardContainerProperty, true);
+
+ position.y += position.height + EditorGUIUtility.standardVerticalSpacing;
+ position.height = EditorGUI.GetPropertyHeight(propertyNameProperty);
+ position.width -= position.height;
+ EditorGUI.PropertyField(position, propertyNameProperty, true);
+
+ position.x += position.width;
+ position.width = position.height;
+
+ bool wasEnabled = GUI.enabled;
+ GUI.enabled = blackboardContainerProperty.objectReferenceValue != null;
+ if (EditorGUI.DropdownButton(position, GUIContent.none, FocusType.Keyboard))
+ {
+ try
+ {
+ FillPropertyNamesCache(serializedContainersProperty);
+ CreateGenericMenu(propertyNameProperty);
+ }
+ finally
+ {
+ s_propertyKeysCache.Clear();
+ }
+ }
+ GUI.enabled = wasEnabled;
+
+ --EditorGUI.indentLevel;
+ }
+
+ private static void FillPropertyNamesCache(SerializedProperty serializedContainersProperty)
+ {
+ if (serializedContainersProperty == null)
+ {
+ return;
+ }
+
+ for (int i = 0, count = serializedContainersProperty.arraySize; i < count; ++i)
+ {
+ SerializedProperty serializedContainerProperty = serializedContainersProperty.GetArrayElementAtIndex(i);
+ var serializedContainer = serializedContainerProperty.objectReferenceValue as SerializedContainer;
+
+ if (serializedContainer == null)
+ {
+ continue;
+ }
+
+ serializedContainer.GetKeys(s_propertyKeysCache);
+ }
+ }
+
+ private static void CreateGenericMenu(SerializedProperty propertyNameProperty)
+ {
+ var menu = new GenericMenu();
+
+ for (int i = 0, count = s_propertyKeysCache.Count; i < count; ++i)
+ {
+ (string propertyKey, Type type) = s_propertyKeysCache[i];
+ var menuItem = new MenuItem(propertyNameProperty, propertyKey);
+ menu.AddItem(new GUIContent($"{propertyKey} : {type.Name}"),
+ false, s_onMenuItem, menuItem);
+ }
+
+ menu.ShowAsContext();
+ }
+
+ private static void OnMenuItem(object menuItemObject)
+ {
+ var menuItem = (MenuItem)menuItemObject;
+ menuItem.propertyNameProperty.stringValue = menuItem.propertyKeyValue;
+ menuItem.propertyNameProperty.serializedObject.ApplyModifiedProperties();
+ }
+
+ private readonly struct MenuItem
+ {
+ public readonly SerializedProperty propertyNameProperty;
+ public readonly string propertyKeyValue;
+
+ public MenuItem(SerializedProperty propertyNameProperty, string propertyKeyValue)
+ {
+ this.propertyNameProperty = propertyNameProperty;
+ this.propertyKeyValue = propertyKeyValue;
+ }
+ }
+ }
+}
diff --git a/Editor/CustomEditors/BlackboardPropertyReferenceEditor.cs.meta b/Editor/CustomEditors/BlackboardPropertyReferenceEditor.cs.meta
new file mode 100644
index 0000000..d6b0d2e
--- /dev/null
+++ b/Editor/CustomEditors/BlackboardPropertyReferenceEditor.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b0011a483a3a42cfb4335ea4ce134073
+timeCreated: 1592154610
\ No newline at end of file
diff --git a/Editor/CustomEditors/GeneratingValueSerializedTableEditor.cs b/Editor/CustomEditors/GeneratingValueSerializedTableEditor.cs
new file mode 100644
index 0000000..06fef30
--- /dev/null
+++ b/Editor/CustomEditors/GeneratingValueSerializedTableEditor.cs
@@ -0,0 +1,114 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using System;
+using UnityEditor;
+using UnityEditorInternal;
+using UnityEngine;
+using Zor.SimpleBlackboard.Debugging;
+
+namespace Zor.SimpleBlackboard.Serialization
+{
+ [CustomEditor(typeof(GeneratedValueSerializedTable_Base), true)]
+ public sealed class GeneratingValueSerializedTableEditor : Editor
+ {
+ private const string KeysPropertyName = "m_Keys";
+
+ private SerializedProperty m_keysProperty;
+ private ReorderableList m_list;
+
+ private bool m_correctType;
+
+ public override void OnInspectorGUI()
+ {
+ if (!m_correctType)
+ {
+ base.OnInspectorGUI();
+ return;
+ }
+
+ m_list.DoLayoutList();
+ }
+
+ private void OnEnable()
+ {
+ Type targetType = target.GetType();
+
+ if (!IsSubclassOfRightClass(targetType))
+ {
+ BlackboardDebug.LogError($"{targetType.FullName} is derived from {typeof(GeneratedValueSerializedTable_Base).FullName}. Instead it should be derived from {typeof(StructGeneratedValueSerializedTable<>).FullName} or {typeof(ClassGeneratedValueSerializedTable<>).FullName}");
+ return;
+ }
+
+ m_correctType = true;
+
+ m_keysProperty = serializedObject.FindProperty(KeysPropertyName);
+
+ m_list = new ReorderableList(serializedObject, m_keysProperty, false, true, true, true)
+ {
+ drawHeaderCallback = OnDrawHeader,
+ elementHeightCallback = OnElementHeight,
+ drawElementCallback = OnDrawElement,
+ onAddCallback = OnAdd,
+ onRemoveCallback = OnRemove
+ };
+ }
+
+ private void OnDrawHeader(Rect rect)
+ {
+ EditorGUI.LabelField(rect, $"{((SerializedTable_Base)target).valueType.Name} ({m_keysProperty.arraySize})");
+ }
+
+ private float OnElementHeight(int index)
+ {
+ SerializedProperty key = m_keysProperty.GetArrayElementAtIndex(index);
+
+ return EditorGUI.GetPropertyHeight(key, new GUIContent("Key"), true)
+ + EditorGUIUtility.standardVerticalSpacing * 2f;
+ }
+
+ private void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused)
+ {
+ SerializedProperty key = m_keysProperty.GetArrayElementAtIndex(index);
+
+ rect.x += 10f;
+ rect.width -= 10f;
+ rect.height = EditorGUI.GetPropertyHeight(key, new GUIContent("Key"),true);
+ EditorGUI.PropertyField(rect, key, new GUIContent("Key"),true);
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ private void OnAdd(ReorderableList list)
+ {
+ m_keysProperty.arraySize++;
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ private void OnRemove(ReorderableList list)
+ {
+ int index = list.index;
+ SerializedPropertyHelper.CompletelyRemove(m_keysProperty, index);
+
+ serializedObject.ApplyModifiedProperties();
+ }
+
+ private static bool IsSubclassOfRightClass(Type toCheck)
+ {
+ while (toCheck != null && toCheck != typeof(object))
+ {
+ Type type = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
+
+ if (typeof(StructGeneratedValueSerializedTable<>) == type ||
+ typeof(ClassGeneratedValueSerializedTable<>) == type)
+ {
+ return true;
+ }
+
+ toCheck = toCheck.BaseType;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/Editor/CustomEditors/GeneratingValueSerializedTableEditor.cs.meta b/Editor/CustomEditors/GeneratingValueSerializedTableEditor.cs.meta
new file mode 100644
index 0000000..758c891
--- /dev/null
+++ b/Editor/CustomEditors/GeneratingValueSerializedTableEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d0c584e32ab22c841b5740460bacb793
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Editor/CustomEditors/SerializedTablesContainerEditor.cs b/Editor/CustomEditors/SerializedTablesContainerEditor.cs
new file mode 100644
index 0000000..110cca6
--- /dev/null
+++ b/Editor/CustomEditors/SerializedTablesContainerEditor.cs
@@ -0,0 +1,122 @@
+// Copyright (c) 2020 Vladimir Popov zor1994@gmail.com https://github.com/ZorPastaman/Simple-Blackboard
+
+using System;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+using Zor.SimpleBlackboard.EditorTools;
+using Object = UnityEngine.Object;
+
+namespace Zor.SimpleBlackboard.Serialization
+{
+ [CustomEditor(typeof(SerializedTablesContainer))]
+ public sealed class SerializedTablesContainerEditor : Editor
+ {
+ private const string SerializedTablesPropertyName = "m_SerializedTables";
+
+ private readonly Dictionary