This commit is contained in:
2025-01-17 13:10:42 +01:00
commit 4536213c91
15115 changed files with 1442174 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3dfa3c8fac2134fdda65f882f5a1a014
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEditor;
namespace Unity.VisualScripting
{
public class EditorPreferencesProvider : Editor
{
[SettingsProvider]
public static SettingsProvider CreateEditorPreferencesProvider()
{
return new EditorPreferencesProviderView();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ba9c71f100044b3a9dca49c8f9e489cb
timeCreated: 1625864018

View File

@@ -0,0 +1,46 @@
using UnityEngine;
using UnityEditor;
namespace Unity.VisualScripting
{
internal class EditorPreferencesProviderView : SettingsProvider
{
private const string Path = "Preferences/Visual Scripting";
private const string Title = "Visual Scripting";
private const string ID = "Bolt";
private readonly GUIStyle marginStyle = new GUIStyle() { margin = new RectOffset(10, 10, 10, 10) };
public EditorPreferencesProviderView() : base(Path, SettingsScope.User)
{
label = Title;
}
private void EnsureConfig()
{
if (BoltCore.instance == null || BoltCore.Configuration == null)
{
PluginContainer.Initialize();
}
}
public override void OnGUI(string searchContext)
{
EnsureConfig();
GUILayout.BeginVertical(marginStyle);
// happens when opening unity with the settings window already opened. there's a delay until the singleton is assigned
if (BoltCore.instance == null)
{
EditorGUILayout.HelpBox("Loading Configuration...", MessageType.Info);
return;
}
var instance = (BoltProduct)ProductContainer.GetProduct(ID);
instance.configurationPanel.PreferenceItem();
GUILayout.EndVertical();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7453dd8d3980405794f631eea9f420e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a06b4d04018343b99f255da7f18559d1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
using UnityEngine;
using UnityEditor;
namespace Unity.VisualScripting
{
public class AssemblyOptionsSettings
{
private const string CompleteLabel = "Regenerate Nodes";
private readonly PluginConfigurationItemMetadata _assemblyOptionsMetadata;
private bool _showAssembly = false;
private const string TitleAssembly = "Node Library";
private const string DescriptionAssembly = "Choose the assemblies in which you want to look for nodes.\n"
+ "By default, all project and Unity assemblies are included.\n"
+ "Unless you use a third-party plugin distributed as a DLL, you shouldn't need to change this.";
private ProjectAssemblyOptionsListInspector _assemblyOptionsInspector;
public AssemblyOptionsSettings(BoltCoreConfiguration coreConfig)
{
_assemblyOptionsMetadata = coreConfig.GetMetadata(nameof(coreConfig.assemblyOptions));
_assemblyOptionsInspector = new ProjectAssemblyOptionsListInspector(_assemblyOptionsMetadata);
}
private static class Styles
{
public static readonly GUIStyle background;
public static readonly GUIStyle defaultsButton;
public const float OptionsWidth = 250;
static Styles()
{
background = new GUIStyle(LudiqStyles.windowBackground);
background.padding = new RectOffset(20, 20, 20, 20);
defaultsButton = new GUIStyle("Button");
defaultsButton.padding = new RectOffset(10, 10, 4, 4);
}
}
public void OnGUI()
{
_showAssembly = EditorGUILayout.Foldout(_showAssembly, new GUIContent(TitleAssembly, DescriptionAssembly));
if (_showAssembly)
{
GUILayout.BeginVertical(Styles.background, GUILayout.ExpandHeight(true));
var height = _assemblyOptionsInspector.GetCachedHeight(Styles.OptionsWidth, GUIContent.none, null);
EditorGUI.BeginChangeCheck();
var position = GUILayoutUtility.GetRect(Styles.OptionsWidth, height);
_assemblyOptionsInspector.Draw(position, GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
_assemblyOptionsMetadata.SaveImmediately(true);
Codebase.UpdateSettings();
}
if (GUILayout.Button("Reset to Defaults", Styles.defaultsButton) && EditorUtility.DisplayDialog("Reset the Node Library", "Reset the Node Library to its default state?", "Reset to Default", "Cancel"))
{
_assemblyOptionsMetadata.Reset(true);
_assemblyOptionsMetadata.SaveImmediately(true);
}
LudiqGUI.EndVertical();
}
if (GUILayout.Button(CompleteLabel, Styles.defaultsButton))
{
UnitBase.Rebuild();
EditorUtility.DisplayDialog("Visual Script", "Regenerate Nodes completed", "OK");
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7cb1615bd41a3442a8aabbcb872046a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
using System.Diagnostics;
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
public class BackupSettings
{
private const string Title = "Backup Graphs";
private const string ButtonBackupLabel = "Create Backup";
private const string ButtonRestoreLabel = "Restore Backup";
public void OnGUI()
{
GUILayout.Space(5f);
GUILayout.Label(Title, EditorStyles.boldLabel);
GUILayout.Space(5f);
if (GUILayout.Button(ButtonBackupLabel, Styles.defaultsButton))
{
VSBackupUtility.Backup();
EditorUtility.DisplayDialog("Backup", "Backup completed successfully.", "OK");
}
if (GUILayout.Button(ButtonRestoreLabel, Styles.defaultsButton))
{
PathUtility.CreateDirectoryIfNeeded(Paths.backups);
Process.Start(Paths.backups);
}
}
private static class Styles
{
static Styles()
{
defaultsButton = new GUIStyle("Button");
defaultsButton.padding = new RectOffset(10, 10, 4, 4);
}
public static readonly GUIStyle defaultsButton;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50455e66302b715488a9218e30b0ab24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
public class CustomPropertyProviderSettings
{
private const string Title = "Custom Inspector Properties";
private const string ButtonLabel = "Generate";
public void OnGUI()
{
GUILayout.Space(5f);
GUILayout.Label(Title, EditorStyles.boldLabel);
GUILayout.Space(5f);
string label = "Inspectors in Visual Scripting plugins can handle many custom types besides Unity primites and objects. ";
label += "However, to be compatible with your custom editor drawers, some additional property provider scripts must be generated. ";
GUILayout.BeginHorizontal(EditorStyles.helpBox);
GUILayout.Label(EditorGUIUtility.IconContent("console.infoicon"), GUILayout.ExpandWidth(true));
GUILayout.Box(label, EditorStyles.wordWrappedLabel);
GUILayout.EndHorizontal();
if (GUILayout.Button(ButtonLabel, Styles.defaultsButton))
{
SerializedPropertyProviderProvider.instance.GenerateProviderScripts();
EditorUtility.DisplayDialog("Custom Inspector Generation", "Custom inspector generation has completed successfully.", "OK");
}
}
private static class Styles
{
static Styles()
{
defaultsButton = new GUIStyle("Button");
defaultsButton.padding = new RectOffset(10, 10, 4, 4);
}
public static readonly GUIStyle defaultsButton;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7da9d8250917648728b856bfab5f1320
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
internal class LinkerPropertyProviderSettings
{
private readonly PluginConfigurationItemMetadata _linkerSettings;
private const string Title = "Linker generation settings";
private readonly GUIContent[] _toggleTargetsLabel =
{
new GUIContent("Scan graph assets"),
new GUIContent("Scan scenes"),
new GUIContent("Scan prefabs")
};
private Array _options = Enum.GetValues(typeof(BoltCoreConfiguration.LinkerScanTarget));
private List<bool> _settings;
public LinkerPropertyProviderSettings(BoltCoreConfiguration coreConfig)
{
_linkerSettings = coreConfig.GetMetadata(nameof(LinkerPropertyProviderSettings));
_settings = new List<bool>((List<bool>)_linkerSettings.value);
}
private void SaveIfNeeded()
{
var settings = (List<bool>)_linkerSettings.value;
if (!_settings.SequenceEqual(settings))
{
_linkerSettings.value = new List<bool>(_settings);
_linkerSettings.SaveImmediately();
}
}
public void OnGUI()
{
GUILayout.Space(5f);
GUILayout.Label(Title, EditorStyles.boldLabel);
GUILayout.Space(5f);
var label = "Scan for types to be added to link.xml";
GUILayout.BeginHorizontal(EditorStyles.helpBox);
GUILayout.Label(EditorGUIUtility.IconContent("console.infoicon"), GUILayout.ExpandWidth(true));
GUILayout.Box(label, EditorStyles.wordWrappedLabel);
GUILayout.EndHorizontal();
GUILayout.Space(5f);
foreach (var option in _options)
{
_settings[(int)option] = GUILayout.Toggle(_settings[(int)option], _toggleTargetsLabel[(int)option]);
GUILayout.Space(5f);
}
SaveIfNeeded();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f2e89b748a6ae452488da87a34e25287
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
public class ScriptReferenceResolverSettings
{
private const string Title = "Script Reference Resolver";
private const string ButtonLabel = "Fix Missing Scripts";
public void OnGUI()
{
GUILayout.Space(5f);
GUILayout.Label(Title, EditorStyles.boldLabel);
GUILayout.Space(5f);
if (GUILayout.Button(ButtonLabel, Styles.defaultsButton))
{
ScriptReferenceResolver.Run(ScriptReferenceResolver.Mode.Dialog);
}
}
private static class Styles
{
static Styles()
{
defaultsButton = new GUIStyle("Button");
defaultsButton.padding = new RectOffset(10, 10, 4, 4);
}
public static readonly GUIStyle defaultsButton;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a8c0a3364f2ef4e42820eb87b5bdab69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
using UnityEditor;
using UnityEngine;
namespace Unity.VisualScripting
{
public class TypeOptionsSettings
{
private readonly PluginConfigurationItemMetadata _typeOptionsMetadata;
private bool _showTypeOption = false;
private const string TitleTypeOption = "Type Options";
private const string DescriptionTypeOption = "Choose the types you want to use for variables and nodes.\n"
+ "MonoBehaviour types are always included.";
private static class Styles
{
public static readonly GUIStyle background;
public static readonly GUIStyle defaultsButton;
public const float OptionsWidth = 250;
static Styles()
{
background = new GUIStyle(LudiqStyles.windowBackground);
background.padding = new RectOffset(20, 20, 20, 20);
defaultsButton = new GUIStyle("Button");
defaultsButton.padding = new RectOffset(10, 10, 4, 4);
}
}
public TypeOptionsSettings(BoltCoreConfiguration coreConfig)
{
_typeOptionsMetadata = coreConfig.GetMetadata(nameof(coreConfig.typeOptions));
}
public void OnGUI()
{
_showTypeOption = EditorGUILayout.Foldout(_showTypeOption, new GUIContent(TitleTypeOption, DescriptionTypeOption));
if (_showTypeOption)
{
GUILayout.BeginVertical(Styles.background, GUILayout.ExpandHeight(true));
float height =
LudiqGUI.GetInspectorHeight(null, _typeOptionsMetadata, Styles.OptionsWidth, GUIContent.none);
EditorGUI.BeginChangeCheck();
var position = GUILayoutUtility.GetRect(Styles.OptionsWidth, height);
LudiqGUI.Inspector(_typeOptionsMetadata, position, GUIContent.none);
if (EditorGUI.EndChangeCheck())
{
_typeOptionsMetadata.SaveImmediately(true);
Codebase.UpdateSettings();
}
if (GUILayout.Button("Reset to Defaults", Styles.defaultsButton) && EditorUtility.DisplayDialog("Reset Included Types", "Reset the included types to their defaults?", "Reset to Default", "Cancel"))
{
_typeOptionsMetadata.Reset(true);
_typeOptionsMetadata.SaveImmediately(true);
}
LudiqGUI.EndVertical();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f061d8e7ad514436d82f47b34306a22c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEditor;
namespace Unity.VisualScripting
{
public class ProjectSettingsProvider : Editor
{
[SettingsProvider]
public static SettingsProvider CreateProjectSettingProvider()
{
return new ProjectSettingsProviderView();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6a0cc840e6084f62a3e3538f14bf3ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,125 @@
using UnityEngine;
using UnityEditor;
namespace Unity.VisualScripting
{
internal class ProjectSettingsProviderView : SettingsProvider
{
private const string Path = "Project/Visual Scripting";
private const string Title = "Visual Scripting";
private const string TitleGroup = "Generate Nodes";
private readonly GUIStyle marginStyle = new GUIStyle() { margin = new RectOffset(10, 10, 10, 10) };
private AssemblyOptionsSettings _assemblyOptionsSettings;
private TypeOptionsSettings _typeOptionsSettings;
private CustomPropertyProviderSettings _customPropertyProviderSettings;
private LinkerPropertyProviderSettings _linkerPropertyProviderSettings;
private BackupSettings _backupSettings;
private ScriptReferenceResolverSettings _scriptReferenceResolverSettings;
private BoltCoreConfiguration _vsCoreConfig = null;
public ProjectSettingsProviderView() : base(Path, SettingsScope.Project)
{
label = Title;
EditorTypeUtility.Initialize();
}
private void CreateOptionsIfNeeded()
{
_assemblyOptionsSettings ??= new AssemblyOptionsSettings(_vsCoreConfig);
_typeOptionsSettings ??= new TypeOptionsSettings(_vsCoreConfig);
_customPropertyProviderSettings ??= new CustomPropertyProviderSettings();
_linkerPropertyProviderSettings ??= new LinkerPropertyProviderSettings(_vsCoreConfig);
_backupSettings ??= new BackupSettings();
_scriptReferenceResolverSettings ??= new ScriptReferenceResolverSettings();
}
private void EnsureConfig()
{
if (_vsCoreConfig != null)
return;
if (BoltCore.instance == null || BoltCore.Configuration == null)
{
UnityAPI.Initialize();
PluginContainer.Initialize();
}
_vsCoreConfig = BoltCore.Configuration;
}
public override void OnGUI(string searchContext)
{
GUILayout.BeginVertical(marginStyle);
if (VSUsageUtility.isVisualScriptingUsed)
{
EnsureConfig();
GUILayout.Space(5f);
GUILayout.Label(TitleGroup, EditorStyles.boldLabel);
GUILayout.Space(10f);
// happens when opening unity with the settings window already opened. there's a delay until the singleton is assigned
if (_vsCoreConfig == null)
{
EditorGUILayout.HelpBox("Loading Configuration...", MessageType.Info);
return;
}
CreateOptionsIfNeeded();
_typeOptionsSettings.OnGUI();
GUILayout.Space(10f);
_assemblyOptionsSettings.OnGUI();
GUILayout.Space(10f);
_customPropertyProviderSettings.OnGUI();
GUILayout.Space(10f);
_linkerPropertyProviderSettings.OnGUI();
GUILayout.Space(10f);
_backupSettings.OnGUI();
GUILayout.Space(10f);
_scriptReferenceResolverSettings.OnGUI();
}
else
{
GUILayout.Space(5f);
GUILayout.BeginHorizontal(EditorStyles.label);
if (GUILayout.Button("Initialize Visual Scripting", Styles.defaultsButton))
{
VSUsageUtility.isVisualScriptingUsed = true;
}
GUILayout.Space(5f);
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
}
private static class Styles
{
static Styles()
{
defaultsButton = new GUIStyle("Button");
defaultsButton.padding = new RectOffset(10, 10, 4, 4);
}
public static readonly GUIStyle defaultsButton;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4eea00f49056f4ee98c82b6923b44600
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
{
"name": "Unity.VisualScripting.SettingsProvider.Editor",
"references": [
"Unity.VisualScripting.Core",
"Unity.VisualScripting.Core.Editor",
"Unity.VisualScripting.Flow",
"Unity.VisualScripting.Flow.Editor",
"Unity.VisualScripting.State"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2aa54ddaa48744e1caddee916e39805e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7abb56c9dd89a544a9995a060ab55368
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a0a037cc0a236493996d666b0ab8690c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
namespace Unity.VisualScripting
{
public abstract class Analyser<TTarget, TAnalysis> : Assigner<TTarget, TAnalysis>, IAnalyser
where TAnalysis : class, IAnalysis, new()
{
protected Analyser(GraphReference reference, TTarget target) : base(target, new TAnalysis())
{
Ensure.That(nameof(reference)).IsNotNull(reference);
this.reference = reference;
// HACK: It makes more sense to think of analysis as reference-bound,
// however in practice they are context-bound and therefore it is safe
// (and more importantly faster) to cache the context once for recursive
// analyses.
this.context = reference.Context();
}
public TAnalysis analysis => assignee;
IAnalysis IAnalyser.analysis => analysis;
protected IGraphContext context { get; }
public GraphReference reference { get; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7cf3624e65e804bfb9dd35ee9884f519
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
using System;
namespace Unity.VisualScripting
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class AnalyserAttribute : Attribute, IDecoratorAttribute
{
public AnalyserAttribute(Type type)
{
this.type = type;
}
public Type type { get; private set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b7663ba3a43454ba48fd2c7c17a0ae75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
using System;
namespace Unity.VisualScripting
{
public sealed class AnalyserProvider : SingleDecoratorProvider<object, IAnalyser, AnalyserAttribute>
{
protected override bool cache => true;
public GraphReference reference { get; }
public AnalyserProvider(GraphReference reference)
{
this.reference = reference;
}
protected override IAnalyser CreateDecorator(Type decoratorType, object decorated)
{
return (IAnalyser)decoratorType.Instantiate(true, reference, decorated);
}
public override bool IsValid(object analyzed)
{
return !analyzed.IsUnityNull();
}
public void Analyze(object analyzed)
{
GetDecorator(analyzed).isDirty = true;
}
public void AnalyzeAll()
{
foreach (var analyser in decorators.Values)
{
analyser.isDirty = true;
}
}
}
public static class XAnalyserProvider
{
// Analysis are conceptually reference-bound, but practically context-bound,
// so it's faster to avoid the reference-to-context lookup if we can avoid it.
public static IAnalyser Analyser(this object target, IGraphContext context)
{
return context.analyserProvider.GetDecorator(target);
}
public static TAnalyser Analyser<TAnalyser>(this object target, IGraphContext context) where TAnalyser : IAnalyser
{
return context.analyserProvider.GetDecorator<TAnalyser>(target);
}
public static IAnalysis Analysis(this object target, IGraphContext context)
{
var analyser = target.Analyser(context);
analyser.Validate();
return analyser.analysis;
}
public static TAnalysis Analysis<TAnalysis>(this object target, IGraphContext context) where TAnalysis : IAnalysis
{
return (TAnalysis)target.Analysis(context);
}
// Shortcuts, but the above are faster because Context doesn't have to be looked up
public static IAnalyser Analyser(this object target, GraphReference reference)
{
return target.Analyser(reference.Context());
}
public static TAnalyser Analyser<TAnalyser>(this object target, GraphReference reference) where TAnalyser : IAnalyser
{
return target.Analyser<TAnalyser>(reference.Context());
}
public static IAnalysis Analysis(this object target, GraphReference reference)
{
return target.Analysis(reference.Context());
}
public static TAnalysis Analysis<TAnalysis>(this object target, GraphReference reference) where TAnalysis : IAnalysis
{
return target.Analysis<TAnalysis>(reference.Context());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8c1743061b8e147ff9c808d137b1014e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
namespace Unity.VisualScripting
{
public abstract class Analysis : IAnalysis
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f01a1ac261c724daca990596c32f7f10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public class GraphElementAnalysis : IGraphElementAnalysis
{
public List<Warning> warnings { get; set; } = new List<Warning>();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ac0dd11da2f64fc5b55b1b8a1d36b55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
namespace Unity.VisualScripting
{
public interface IAnalyser
{
IAnalysis analysis { get; }
bool isDirty { get; set; }
void Validate();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b1eb0e9411d1e4ed880da3147ac22dc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
namespace Unity.VisualScripting
{
public interface IAnalysis
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4fb36d0252722495cbe1fddf45ba9185
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Unity.VisualScripting
{
public interface IGraphElementAnalysis : IAnalysis
{
List<Warning> warnings { get; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf7f2015398494d498495147f2028b49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fae0344df02e74e0988c577297cc556d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using System;
using UnityEditor;
using UnityEngine.Analytics;
namespace Unity.VisualScripting
{
public sealed class UsageAnalytics
{
const int k_MaxEventsPerHour = 1000;
const int k_MaxNumberOfElements = 1000;
const string k_VendorKey = "unity.bolt";
const string k_EventName = "BoltUsage";
#if !UNITY_2023_2_OR_NEWER
static bool isRegistered = false;
#endif
internal static void CollectAndSendForType<T>(string[] paths)
{
if (!EditorAnalytics.enabled || !VSUsageUtility.isVisualScriptingUsed)
return;
foreach (string path in paths)
{
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(path);
if (assetType == typeof(T))
{
CollectAndSend();
return;
}
}
}
#if UNITY_2023_2_OR_NEWER
public static void CollectAndSend()
{
if (!EditorAnalytics.enabled || !VSUsageUtility.isVisualScriptingUsed)
return;
EditorAnalytics.SendAnalytic(new UsageAnalytic(CollectData()));
}
#else
public static void CollectAndSend()
{
if (!EditorAnalytics.enabled || !VSUsageUtility.isVisualScriptingUsed)
return;
if (!RegisterEvent())
return;
var data = CollectData();
EditorAnalytics.SendEventWithLimit(k_EventName, data);
}
private static bool RegisterEvent()
{
if (!isRegistered)
{
var result = EditorAnalytics.RegisterEventWithLimit(k_EventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey);
if (result == UnityEngine.Analytics.AnalyticsResult.Ok)
{
isRegistered = true;
}
}
return isRegistered;
}
#endif
private static UsageAnalyticsData CollectData()
{
var data = new UsageAnalyticsData
{
productVersion = BoltProduct.instance.version.ToString(),
};
return data;
}
#if UNITY_2023_2_OR_NEWER
[AnalyticInfo(eventName: k_EventName, vendorKey: k_VendorKey, maxEventsPerHour:k_MaxEventsPerHour, maxNumberOfElements:k_MaxNumberOfElements)]
class UsageAnalytic : IAnalytic
{
private UsageAnalyticsData data;
public UsageAnalytic(UsageAnalyticsData data)
{
this.data = data;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
error = null;
data = this.data;
return data != null;
}
}
private struct UsageAnalyticsData: IAnalytic.IData
#else
private struct UsageAnalyticsData
#endif
{
public string productVersion;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 59718df20b933421a9c465fcbeff7836
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
using System;
using System.Text.RegularExpressions;
namespace Unity.VisualScripting.Analytics
{
internal static class AnalyticsUtilities
{
internal static string AnonymizeException(Exception e)
{
const string pathSectionOutsidePackage = "in (?<P>.*)Packages\\\\com.unity.visualscripting";
// Placing a '^' character to distinguish these lines from file paths outside our package
const string pathSectionOutsidePackageReplacement = "in ^Packages\\com.unity.visualscripting";
var anonymizedString = Regex.Replace(e.ToString(), pathSectionOutsidePackage, pathSectionOutsidePackageReplacement);
// Detecting any callstack line that doesn't match our previously anonymized package paths
const string filePathsOutsidePackage = ". at.*in (?<P>[^^]*:[0-9]*)";
const string filePathsOutsidePackageReplacement = " at <method> in <file>";
anonymizedString = Regex.Replace(anonymizedString, filePathsOutsidePackage,
filePathsOutsidePackageReplacement);
return anonymizedString;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7d2bbdd7f3404e04941d986015e27acb
timeCreated: 1621016306

View File

@@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Analytics;
namespace Unity.VisualScripting.Analytics
{
internal static class HotkeyUsageAnalytics
{
private const int MaxEventsPerHour = 120;
private const int MaxNumberOfElements = 1000;
private const string VendorKey = "unity.visualscripting";
private const string EventName = "VScriptHotkeyUsage";
#if !UNITY_2023_2_OR_NEWER
private static bool _isRegistered = false;
#endif
private const int HotkeyUseLimitBeforeSend = 10000;
private static bool _interruptEventsRegistered = false;
private static bool _onControlSchemeEventRegistered = false;
private static Data _collectedData = null;
// Limiting to stop spam from some continuous events like pan or zoom
private const int HotkeyFrameLimit = 2;
private static Dictionary<Hotkey, FrameLimiterUtility> _frameLimiters;
internal static void HotkeyUsed(Hotkey key)
{
EnsureCollectedDataInitialized();
EnsureInterruptEventsRegistered();
EnsureOnControlSchemeChangedRegistered();
_collectedData.canvasControlSchemeName = Enum.GetName(typeof(CanvasControlScheme), BoltCore.Configuration.controlScheme);
if (!_frameLimiters.ContainsKey(key))
_frameLimiters.Add(key, new FrameLimiterUtility(HotkeyFrameLimit));
if (!_frameLimiters[key].IsWithinFPSLimit()) return;
var enumStringVal = Enum.GetName(typeof(Hotkey), key);
if (enumStringVal == null)
return;
if (!_collectedData.HotkeyUsageCountDict.ContainsKey(enumStringVal))
_collectedData.HotkeyUsageCountDict.Add(enumStringVal, 0);
_collectedData.HotkeyUsageCountDict[enumStringVal]++;
if (_collectedData.HotkeyUsageCountDict[enumStringVal] >= HotkeyUseLimitBeforeSend)
Send();
}
#if UNITY_2023_2_OR_NEWER
private static void Send()
{
if (!EditorAnalytics.enabled)
return;
// Because dicts aren't serializable, convert it to a list right before we send
foreach (var count in _collectedData.HotkeyUsageCountDict)
{
var c = new HotkeyStringUsageCount();
c.hotkey = count.Key;
c.count = count.Value;
_collectedData.hotkeyUsageCount.Add(c);
}
EditorAnalytics.SendAnalytic(new HotkeyUsageAnalytic(_collectedData));
ResetCollectedData();
}
#else
private static void Send()
{
if (!EditorAnalytics.enabled)
return;
if (!RegisterEvent())
return;
// Because dicts aren't serializable, convert it to a list right before we send
foreach (var count in _collectedData.HotkeyUsageCountDict)
{
var c = new HotkeyStringUsageCount();
c.hotkey = count.Key;
c.count = count.Value;
_collectedData.hotkeyUsageCount.Add(c);
}
EditorAnalytics.SendEventWithLimit(EventName, _collectedData);
ResetCollectedData();
}
private static bool RegisterEvent()
{
if (!_isRegistered)
{
var result = EditorAnalytics.RegisterEventWithLimit(EventName, MaxEventsPerHour, MaxNumberOfElements, VendorKey);
if (result == UnityEngine.Analytics.AnalyticsResult.Ok)
{
_isRegistered = true;
}
}
return _isRegistered;
}
#endif
private static void EnsureInterruptEventsRegistered()
{
if (_interruptEventsRegistered) return;
EditorApplication.quitting += Send;
AssemblyReloadEvents.beforeAssemblyReload += Send;
_interruptEventsRegistered = true;
}
private static void EnsureOnControlSchemeChangedRegistered()
{
if (_onControlSchemeEventRegistered) return;
BoltCore.Configuration.ControlSchemeChanged += Send;
_onControlSchemeEventRegistered = true;
}
private static void EnsureCollectedDataInitialized()
{
if (_collectedData != null) return;
ResetCollectedData();
_frameLimiters = new Dictionary<Hotkey, FrameLimiterUtility>();
}
private static void ResetCollectedData()
{
var controlScheme = Enum.GetName(typeof(CanvasControlScheme), BoltCore.Configuration.controlScheme);
_collectedData = new Data()
{
canvasControlSchemeName = controlScheme,
hotkeyUsageCount = new List<HotkeyStringUsageCount>(),
HotkeyUsageCountDict = new Dictionary<string, int>(),
};
}
#if UNITY_2023_2_OR_NEWER
[AnalyticInfo(eventName: EventName, vendorKey: VendorKey, maxEventsPerHour:MaxEventsPerHour, maxNumberOfElements:MaxNumberOfElements)]
class HotkeyUsageAnalytic : IAnalytic
{
private Data data;
public HotkeyUsageAnalytic(Data data)
{
this.data = data;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
error = null;
data = this.data;
return data != null;
}
}
[Serializable]
private class Data : IAnalytic.IData
#else
[Serializable]
private class Data
#endif
{
// Note: using strings instead of enums to make it resilient to enum order changing
[SerializeField]
internal string canvasControlSchemeName;
[SerializeField]
internal List<HotkeyStringUsageCount> hotkeyUsageCount;
// Not actually sent to analytics because analytics uses UnitySerializer under the hood
// which cannot serialize dictionaries
internal Dictionary<string, int> HotkeyUsageCountDict;
}
[Serializable]
private struct HotkeyStringUsageCount
{
[SerializeField] internal string hotkey;
[SerializeField] internal int count;
}
internal enum Hotkey
{
Zoom,
Scroll,
PanMmb,
PanAltLmb,
Home,
RmbRemoveConnections,
Cut,
Copy,
Paste,
Duplicate,
Delete,
SelectAll,
Tab,
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5e84744b83a8434ab42fa513f9bf00ad
timeCreated: 1617297094

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Analytics;
namespace Unity.VisualScripting.Analytics
{
internal static class MigrationAnalytics
{
private const int MaxEventsPerHour = 120;
private const int MaxNumberOfElements = 1000;
private const string VendorKey = "unity.visualscripting";
private const string EventName = "VScriptMigration";
#if !UNITY_2023_2_OR_NEWER
private static bool _isRegistered = false;
#endif
#if UNITY_2023_2_OR_NEWER
internal static void Send(Data data)
{
if (!EditorAnalytics.enabled)
return;
EditorAnalytics.SendAnalytic(new MigrationAnalytic(data));
}
#else
internal static void Send(Data data)
{
if (!EditorAnalytics.enabled)
return;
if (!RegisterEvent())
return;
EditorAnalytics.SendEventWithLimit(EventName, data);
}
private static bool RegisterEvent()
{
if (!_isRegistered)
{
var result = EditorAnalytics.RegisterEventWithLimit(EventName, MaxEventsPerHour, MaxNumberOfElements, VendorKey);
if (result == UnityEngine.Analytics.AnalyticsResult.Ok)
{
_isRegistered = true;
}
}
return _isRegistered;
}
#endif
#if UNITY_2023_2_OR_NEWER
[AnalyticInfo(eventName: EventName, vendorKey: VendorKey, maxEventsPerHour:MaxEventsPerHour, maxNumberOfElements:MaxNumberOfElements)]
class MigrationAnalytic : IAnalytic
{
private Data data;
public MigrationAnalytic(Data data)
{
this.data = data;
}
public bool TryGatherData(out IAnalytic.IData data, out Exception error)
{
error = null;
data = this.data;
return data != null;
}
}
[Serializable]
internal class Data : IAnalytic.IData
#else
[Serializable]
internal class Data
#endif
{
[SerializeField]
internal MigrationStepAnalyticsData total;
[SerializeField]
internal List<MigrationStepAnalyticsData> steps;
}
[Serializable]
internal class MigrationStepAnalyticsData
{
[SerializeField]
internal string pluginId;
[SerializeField]
internal string from;
[SerializeField]
internal string to;
[SerializeField]
internal bool success;
[SerializeField]
internal string exception;
}
}
}

Some files were not shown because too many files have changed in this diff Show More