first commit
This commit is contained in:
commit
aa44d3ad70
1585 changed files with 277994 additions and 0 deletions
8
Assets/Plugins/Android.meta
Normal file
8
Assets/Plugins/Android.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9aef7c62457950a4dbd8c7b47aa5b90c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
16
Assets/Plugins/Android/AndroidManifest.xml.DISABLED
Normal file
16
Assets/Plugins/Android/AndroidManifest.xml.DISABLED
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.unity3d.player"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<application>
|
||||
<activity android:name="com.unity3d.player.UnityPlayerActivity"
|
||||
android:theme="@style/UnityThemeSelector">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
7
Assets/Plugins/Android/AndroidManifest.xml.DISABLED.meta
Normal file
7
Assets/Plugins/Android/AndroidManifest.xml.DISABLED.meta
Normal file
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9a62385b990df247a5aad8c487d12dd
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist.meta
Normal file
8
Assets/Plugins/CodeAssist.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 545d0594bfe17884bae9c38e89826081
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
120
Assets/Plugins/CodeAssist/CHANGELOG.TXT
Normal file
120
Assets/Plugins/CodeAssist/CHANGELOG.TXT
Normal file
|
@ -0,0 +1,120 @@
|
|||
List of new features, bug fixes and improvements
|
||||
|
||||
# Version 1.1.9
|
||||
* Gpt support for chat and edit
|
||||
* More options added for Gpt
|
||||
* Overall stability improvements
|
||||
* Exporter shows file locks if update/export is unsuccessful
|
||||
|
||||
# Version 1.1.8
|
||||
* Bugfix for non-Unity solutions
|
||||
|
||||
# Version 1.1.7
|
||||
* Bugfix for Visual Studio freeze
|
||||
|
||||
# Version 1.1.6
|
||||
* Gpt support added for shader files
|
||||
* Stability improvements for Unity.ScriptFinder
|
||||
|
||||
# Version 1.1.5
|
||||
* Stability and usability improvements for exporter/updater
|
||||
* Bugfix for Transformer Linq and Auto Input Manager
|
||||
* Usability for Transformer window, disabling it if not connected to Unity
|
||||
* Enhancement for completions, sorting numerical values correctly https://github.com/merryyellow/Unity-Code-Assist/issues/6
|
||||
|
||||
# Version 1.1.4
|
||||
* Auto Input Manager is now compatible with binary asset files
|
||||
* Stability and usability improvements for Transformer windows
|
||||
|
||||
# Version 1.1.3
|
||||
* Analyzers are working at a separate process https://github.com/merryyellow/Unity-Code-Assist/issues/20
|
||||
* Inline visuals stability and performance improvements https://github.com/merryyellow/Unity-Code-Assist/issues/22 https://github.com/merryyellow/Unity-Code-Assist/issues/24
|
||||
* Exporter/updater stability improvements https://github.com/merryyellow/Unity-Code-Assist/issues/19 https://github.com/merryyellow/Unity-Code-Assist/issues/23
|
||||
* Transformer window stability improvements https://github.com/merryyellow/Unity-Code-Assist/issues/21
|
||||
* Bugfix for Gpt busy icon positioning https://github.com/merryyellow/Unity-Code-Assist/issues/24
|
||||
|
||||
# Version 1.1.2
|
||||
* Bugfix for Yaml file parsing of InputManager
|
||||
|
||||
# Version 1.1.1
|
||||
* Bugfix for error handling of binary file parsing
|
||||
|
||||
# Version 1.1.0
|
||||
* New feature: Generative AI. Use OpenAI ChatGPT within comments to complete your code
|
||||
* New feature: Visual Studio menus. Access Unity Code Assist from "Extensions"->"Unity Code Assist"
|
||||
* New code completions: PlayerPrefs, EditorPrefs and Input classes' methods can be auto completed
|
||||
* New inline visuals: PlayerPrefs, EditorPrefs and Input classes' methods can display inline information
|
||||
* New code transformer: Auto Input Manager. Converts legacy input code into the new Input Manager
|
||||
|
||||
# Version 1.0.0.21
|
||||
* Stability improvements for Unity ScriptFinder class
|
||||
|
||||
# Version 1.0.0.20
|
||||
* Bugfix for crash at startup https://github.com/merryyellow/Unity-Code-Assist/issues/18
|
||||
|
||||
# Version 1.0.0.19
|
||||
* More logging for error tracking
|
||||
|
||||
# Version 1.0.0.18
|
||||
* Overall stability improvements, nullable references enabled for codebase
|
||||
* Stability improvements for communications, when reconnection occurs
|
||||
|
||||
# Version 1.0.0.17
|
||||
* Stability improvements for Unity ScriptFinder class
|
||||
|
||||
# Version 1.0.0.16
|
||||
* Bugfix for Visual Studio events concurrency
|
||||
|
||||
# Version 1.0.0.15
|
||||
* Visual Studio events are reimplemented for both stability and performance
|
||||
* Removal of possible Task deadlocks
|
||||
* Usability improvements for exporter/updater
|
||||
* Bugfix for exporter/updater, where prompts can appear twice
|
||||
* Bugfix for Inline Texts, where const null identifier may raise exceptions https://github.com/merryyellow/Unity-Code-Assist/issues/16
|
||||
* Bugfix for communications, where tags&layers are sent for the first time
|
||||
|
||||
# Version 1.0.0.14
|
||||
* Usability improvements for Visual Studio Status window where project is not a Unity project
|
||||
* Bugfix for communication reinitialization, where projects are closed and opened from Visual Studio https://github.com/merryyellow/Unity-Code-Assist/issues/15
|
||||
* Bugfix for Visual Studio events' initialization https://github.com/merryyellow/Unity-Code-Assist/issues/14
|
||||
|
||||
# Version 1.0.0.13
|
||||
* Bugfix for Unity where target object is neither Component nor MonoBehaviour https://github.com/merryyellow/Unity-Code-Assist/issues/13
|
||||
|
||||
# Version 1.0.0.12
|
||||
* New Feature: Updating Unity asset from Visual Studio
|
||||
* New Feature: Online error reporting of Unity errors
|
||||
* Usability improvement for Visual Studio Feedback window
|
||||
* Bugfix for Inline Texts where there is no class declaration https://github.com/merryyellow/Unity-Code-Assist/issues/5
|
||||
* Bugfix for Code Completion where there is no class declaration https://github.com/merryyellow/Unity-Code-Assist/issues/10
|
||||
* Bugfix for Visual Studio output window, where it may be unavailable
|
||||
|
||||
# Version 1.0.0.11
|
||||
* Bugfix for Visual Studio events' initialization https://github.com/merryyellow/Unity-Code-Assist/issues/3
|
||||
* Exporter now has more logs
|
||||
|
||||
# Version 1.0.0.10
|
||||
* Bugfix for Inline Texts where leading trivia is absent https://github.com/merryyellow/Unity-Code-Assist/issues/1
|
||||
* Bugfix for Visual Studio events' initialization https://github.com/merryyellow/Unity-Code-Assist/issues/2
|
||||
|
||||
# Version 1.0.0.9
|
||||
* Minor adjustments for initialization logging
|
||||
|
||||
# Version 1.0.0.8
|
||||
* Online analytics added
|
||||
* Bugfix for Inline Texts, Visual Studio code preview screen does not raise any exception anymore
|
||||
|
||||
# Version 1.0.0.7
|
||||
* Online error tracker added
|
||||
|
||||
# Version 1.0.0.6
|
||||
* Exporter is always disabled for non Unity projects
|
||||
|
||||
# Version 1.0.0.5
|
||||
* Lite version released at Visual Studio Marketplace
|
||||
* Exporting Unity asset from Visual Studio
|
||||
* Unity package become package independent (Removed Newtonsoft.Json dependency)
|
||||
|
||||
# Version 1.0.0
|
||||
* First release!
|
||||
* Released on Unity Asset Store
|
7
Assets/Plugins/CodeAssist/CHANGELOG.TXT.meta
Normal file
7
Assets/Plugins/CodeAssist/CHANGELOG.TXT.meta
Normal file
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b816ac27e58136e4ea56191b59ebc307
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 79d2263cd3c441a43bc73e708b4e2f22
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
65
Assets/Plugins/CodeAssist/Editor/AboutWindow.cs
Normal file
65
Assets/Plugins/CodeAssist/Editor/AboutWindow.cs
Normal file
|
@ -0,0 +1,65 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
public class AboutWindow : EditorWindow
|
||||
{
|
||||
GUIStyle? styleLabel;
|
||||
|
||||
public static void Display()
|
||||
{
|
||||
// Get existing open window or if none, make a new one:
|
||||
var window = GetWindow<AboutWindow>();
|
||||
window.Show();
|
||||
|
||||
Serilog.Log.Debug("Displaying about window");
|
||||
|
||||
NetMQInitializer.Publisher?.SendAnalyticsEvent("Gui", "AboutWindow_Display");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
//**--icon
|
||||
//var icon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Sprites/Gear.png");
|
||||
//titleContent = new GUIContent("Code Assist", icon);
|
||||
titleContent = new GUIContent("Code Assist About");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
styleLabel ??= new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
wordWrap = true,
|
||||
alignment = TextAnchor.MiddleLeft,
|
||||
};
|
||||
|
||||
EditorGUILayout.LabelField($"Version number: {Assister.Version}", styleLabel, GUILayout.ExpandWidth(true));
|
||||
|
||||
#if MERYEL_UCA_LITE_VERSION
|
||||
EditorGUILayout.LabelField($"License type: Lite", styleLabel, GUILayout.ExpandWidth(true));
|
||||
#else // MERYEL_UCA_LITE_VERSION
|
||||
EditorGUILayout.LabelField($"License type: Full", styleLabel, GUILayout.ExpandWidth(true));
|
||||
#endif // MERYEL_UCA_LITE_VERSION
|
||||
|
||||
if (GUILayout.Button("View changelog"))
|
||||
{
|
||||
Application.OpenURL("https://unitycodeassist.netlify.app/changelog");
|
||||
}
|
||||
|
||||
if (GUILayout.Button("View third party notices"))
|
||||
{
|
||||
Application.OpenURL("https://unitycodeassist.netlify.app/thirdpartynotices");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/AboutWindow.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/AboutWindow.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b2aee5311fd620c4393b0ba06cb90476
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
263
Assets/Plugins/CodeAssist/Editor/Assister.cs
Normal file
263
Assets/Plugins/CodeAssist/Editor/Assister.cs
Normal file
|
@ -0,0 +1,263 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
public class Assister
|
||||
{
|
||||
public const string Version = "1.1.9";
|
||||
|
||||
#if MERYEL_UCA_LITE_VERSION
|
||||
public const string Title = "Code Assist Lite";
|
||||
#else
|
||||
public const string Title = "Code Assist";
|
||||
#endif
|
||||
|
||||
[MenuItem("Tools/" + Title + "/Status", false, 1)]
|
||||
static void DisplayStatusWindow()
|
||||
{
|
||||
StatusWindow.Display();
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Tools/" + Title + "/Synchronize", false, 2)]
|
||||
static void Sync()
|
||||
{
|
||||
EditorCoroutines.EditorCoroutineUtility.StartCoroutine(SyncAux(), NetMQInitializer.Publisher);
|
||||
|
||||
//NetMQInitializer.Publisher.SendConnect();
|
||||
//Serilog.Log.Information("Code Assist is looking for more IDEs to connect to...");
|
||||
|
||||
NetMQInitializer.Publisher?.SendAnalyticsEvent("Gui", "Synchronize_MenuItem");
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Tools/" + Title + "/Report error", false, 51)]
|
||||
static void DisplayFeedbackWindow()
|
||||
{
|
||||
FeedbackWindow.Display();
|
||||
}
|
||||
|
||||
[MenuItem("Tools/" + Title + "/About", false, 52)]
|
||||
static void DisplayAboutWindow()
|
||||
{
|
||||
AboutWindow.Display();
|
||||
}
|
||||
|
||||
#if MERYEL_UCA_LITE_VERSION
|
||||
[MenuItem("Tools/" + Title + "/Compare versions", false, 31)]
|
||||
static void CompareVersions()
|
||||
{
|
||||
Application.OpenURL("http://unitycodeassist.netlify.app/compare");
|
||||
|
||||
NetMQInitializer.Publisher?.SendAnalyticsEvent("Gui", "CompareVersions_MenuItem");
|
||||
}
|
||||
|
||||
[MenuItem("Tools/" + Title + "/Get full version", false, 32)]
|
||||
static void GetFullVersion()
|
||||
{
|
||||
Application.OpenURL("http://u3d.as/2N2H");
|
||||
|
||||
NetMQInitializer.Publisher?.SendAnalyticsEvent("Gui", "FullVersion_MenuItem");
|
||||
}
|
||||
#endif // MERYEL_UCA_LITE_VERSION
|
||||
|
||||
|
||||
static IEnumerator SyncAux()
|
||||
{
|
||||
var clientCount = NetMQInitializer.Publisher?.clients.Count ?? 0;
|
||||
NetMQInitializer.Publisher?.SendConnect();
|
||||
Serilog.Log.Information("Code Assist is looking for more IDEs to connect to...");
|
||||
|
||||
//yield return new WaitForSeconds(3);
|
||||
yield return new EditorCoroutines.EditorWaitForSeconds(3);
|
||||
|
||||
var newClientCount = NetMQInitializer.Publisher?.clients.Count ?? 0;
|
||||
|
||||
var dif = newClientCount - clientCount;
|
||||
|
||||
if (dif <= 0)
|
||||
Serilog.Log.Information("Code Assist couldn't find any new IDE to connect to.");
|
||||
else
|
||||
Serilog.Log.Information("Code Assist is connected to {Dif} new IDE(s).", dif);
|
||||
}
|
||||
|
||||
#if MERYEL_DEBUG
|
||||
|
||||
[MenuItem("Code Assist/Binary2Text")]
|
||||
static void Binary2Text()
|
||||
{
|
||||
var filePath = CommonTools.GetInputManagerFilePath();
|
||||
var hash = Input.UnityInputManager.GetMD5Hash(filePath);
|
||||
var convertedPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"UCA_IM_{hash}.txt");
|
||||
|
||||
var b = new Input.Binary2TextExec();
|
||||
b.Exec(filePath, convertedPath, detailed: false, largeBinaryHashOnly: false, hexFloat: false);
|
||||
}
|
||||
|
||||
[MenuItem("Code Assist/Bump InputManager")]
|
||||
static void BumpInputManager()
|
||||
{
|
||||
Input.InputManagerMonitor.Instance.Bump();
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Code Assist/Layer Check")]
|
||||
static void UpdateLayers()
|
||||
{
|
||||
var names = UnityEditorInternal.InternalEditorUtility.layers;
|
||||
var indices = names.Select(l => LayerMask.NameToLayer(l).ToString()).ToArray();
|
||||
NetMQInitializer.Publisher?.SendLayers(indices, names);
|
||||
|
||||
var sls = SortingLayer.layers;
|
||||
var sortingNames = sls.Select(sl => sl.name).ToArray();
|
||||
var sortingIds = sls.Select(sl => sl.id.ToString()).ToArray();
|
||||
var sortingValues = sls.Select(sl => sl.value.ToString()).ToArray();
|
||||
|
||||
NetMQInitializer.Publisher?.SendSortingLayers(sortingNames, sortingIds, sortingValues);
|
||||
|
||||
/*
|
||||
for (var i = 0; i < 32; i++)
|
||||
{
|
||||
var name = LayerMask.LayerToName(i);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
Debug.Log(i + ":" + name);
|
||||
}
|
||||
}
|
||||
|
||||
if (ScriptFinder.FindGameObjectOfType("Deneme", out var go))
|
||||
NetMQInitializer.Publisher.SendGameObject(go);
|
||||
*/
|
||||
}
|
||||
|
||||
[MenuItem("Code Assist/Tag Check")]
|
||||
static void UpdateTags()
|
||||
{
|
||||
Serilog.Log.Debug("Listing tags {Count}", UnityEditorInternal.InternalEditorUtility.tags.Length);
|
||||
|
||||
foreach (var tag in UnityEditorInternal.InternalEditorUtility.tags)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(tag))
|
||||
{
|
||||
Serilog.Log.Debug("{Tag}", tag);
|
||||
}
|
||||
}
|
||||
|
||||
NetMQInitializer.Publisher?.SendTags(UnityEditorInternal.InternalEditorUtility.tags);
|
||||
|
||||
}
|
||||
|
||||
[MenuItem("Code Assist/GO Check")]
|
||||
|
||||
static void TestGO()
|
||||
{
|
||||
|
||||
var go = GameObject.Find("Deneme");
|
||||
//var go = MonoBehaviour.FindObjectOfType<Deneme>().gameObject;
|
||||
|
||||
NetMQInitializer.Publisher?.SendGameObject(go);
|
||||
}
|
||||
|
||||
[MenuItem("Code Assist/Undo Records Test")]
|
||||
static void UndoTest()
|
||||
{
|
||||
var undos = new List<string>();
|
||||
var redos = new List<string>();
|
||||
|
||||
var type = typeof(Undo);
|
||||
System.Reflection.MethodInfo dynMethod = type.GetMethod("GetRecords",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
dynMethod.Invoke(null, new object[] { undos, redos });
|
||||
|
||||
Serilog.Log.Debug("undos:{UndoCount},redos:{RedoCount}", undos.Count, redos.Count);
|
||||
|
||||
var last = undos.LastOrDefault();
|
||||
if (last != null)
|
||||
{
|
||||
Serilog.Log.Debug("last:{Last}", last);
|
||||
Serilog.Log.Debug("group:{UndoCurrentGroup},{UndoCurrentGroupName}",
|
||||
Undo.GetCurrentGroup(), Undo.GetCurrentGroupName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Code Assist/Undo List Test")]
|
||||
static void Undo2Test()
|
||||
{
|
||||
|
||||
//List<string> undoList, out int undoCursor
|
||||
var undoList = new List<string>();
|
||||
int undoCursor = int.MaxValue;
|
||||
var type = typeof(Undo);
|
||||
System.Reflection.MethodInfo dynMethod = type.GetMethod("GetUndoList",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
|
||||
dynMethod = type.GetMethod("GetUndoList",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static,
|
||||
null,
|
||||
new System.Type[] { typeof(List<string>), typeof(int).MakeByRefType() },
|
||||
null);
|
||||
|
||||
|
||||
dynMethod.Invoke(null, new object[] { undoList, undoCursor });
|
||||
|
||||
Serilog.Log.Debug("undo count: {Count}", undoList.Count);
|
||||
|
||||
}
|
||||
|
||||
[MenuItem("Code Assist/Reload Domain")]
|
||||
static void ReloadDomain()
|
||||
{
|
||||
EditorUtility.RequestScriptReload();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[MenuItem("Code Assist/TEST")]
|
||||
static void TEST()
|
||||
{
|
||||
//if (ScriptFinder.FindGameObjectOfType("Deneme_OtherScene", out var go))
|
||||
if (ScriptFinder.FindInstanceOfType("Deneme_SO", out var go, out var so))
|
||||
{
|
||||
NetMQInitializer.Publisher.SendScriptableObject(so);
|
||||
}
|
||||
|
||||
ScriptFinder.DENEMEEEE();
|
||||
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // MERYEL_DEBUG
|
||||
|
||||
|
||||
public static void SendTagsAndLayers()
|
||||
{
|
||||
Serilog.Log.Debug(nameof(SendTagsAndLayers));
|
||||
|
||||
var tags = UnityEditorInternal.InternalEditorUtility.tags;
|
||||
NetMQInitializer.Publisher?.SendTags(tags);
|
||||
|
||||
var names = UnityEditorInternal.InternalEditorUtility.layers;
|
||||
var indices = names.Select(l => LayerMask.NameToLayer(l).ToString()).ToArray();
|
||||
NetMQInitializer.Publisher?.SendLayers(indices, names);
|
||||
|
||||
var sls = SortingLayer.layers;
|
||||
var sortingNames = sls.Select(sl => sl.name).ToArray();
|
||||
var sortingIds = sls.Select(sl => sl.id.ToString()).ToArray();
|
||||
var sortingValues = sls.Select(sl => sl.value.ToString()).ToArray();
|
||||
NetMQInitializer.Publisher?.SendSortingLayers(sortingNames, sortingIds, sortingValues);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Assister.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Assister.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 13b841023080a994d99f5a6aed7bcb29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
16
Assets/Plugins/CodeAssist/Editor/CodeAssistAssembly.asmdef
Normal file
16
Assets/Plugins/CodeAssist/Editor/CodeAssistAssembly.asmdef
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "Meryel.CodeAssist.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7dbe264750f8c1a44ae4b49065b068ec
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor/EditorCoroutines.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor/EditorCoroutines.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38ac97ab60822544f9cb266c1596645f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
/// <summary>
|
||||
/// A handle to an EditorCoroutine, can be passed to <see cref="EditorCoroutineUtility">EditorCoroutineUtility</see> methods to control lifetime.
|
||||
/// </summary>
|
||||
public class EditorCoroutine
|
||||
{
|
||||
private struct YieldProcessor
|
||||
{
|
||||
enum DataType : byte
|
||||
{
|
||||
None = 0,
|
||||
WaitForSeconds = 1,
|
||||
EditorCoroutine = 2,
|
||||
AsyncOP = 3,
|
||||
}
|
||||
struct ProcessorData
|
||||
{
|
||||
public DataType type;
|
||||
public double targetTime;
|
||||
public object current;
|
||||
}
|
||||
|
||||
ProcessorData data;
|
||||
|
||||
public void Set(object yield)
|
||||
{
|
||||
if (yield == data.current)
|
||||
return;
|
||||
|
||||
var type = yield.GetType();
|
||||
var dataType = DataType.None;
|
||||
double targetTime = -1;
|
||||
|
||||
if(type == typeof(EditorWaitForSeconds))
|
||||
{
|
||||
targetTime = EditorApplication.timeSinceStartup + (yield as EditorWaitForSeconds).WaitTime;
|
||||
dataType = DataType.WaitForSeconds;
|
||||
}
|
||||
else if(type == typeof(EditorCoroutine))
|
||||
{
|
||||
dataType = DataType.EditorCoroutine;
|
||||
}
|
||||
else if(type == typeof(AsyncOperation) || type.IsSubclassOf(typeof(AsyncOperation)))
|
||||
{
|
||||
dataType = DataType.AsyncOP;
|
||||
}
|
||||
|
||||
data = new ProcessorData { current = yield, targetTime = targetTime, type = dataType };
|
||||
}
|
||||
|
||||
public bool MoveNext(IEnumerator enumerator)
|
||||
{
|
||||
var advance = data.type switch
|
||||
{
|
||||
DataType.WaitForSeconds => data.targetTime <= EditorApplication.timeSinceStartup,
|
||||
DataType.EditorCoroutine => (data.current as EditorCoroutine).m_IsDone,
|
||||
DataType.AsyncOP => (data.current as AsyncOperation).isDone,
|
||||
_ => data.current == enumerator.Current,//a IEnumerator or a plain object was passed to the implementation
|
||||
};
|
||||
if (advance)
|
||||
{
|
||||
data = default;// (ProcessorData);
|
||||
return enumerator.MoveNext();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal WeakReference m_Owner;
|
||||
IEnumerator m_Routine;
|
||||
YieldProcessor m_Processor;
|
||||
|
||||
bool m_IsDone;
|
||||
|
||||
internal EditorCoroutine(IEnumerator routine)
|
||||
{
|
||||
m_Owner = null;
|
||||
m_Routine = routine;
|
||||
EditorApplication.update += MoveNext;
|
||||
}
|
||||
|
||||
internal EditorCoroutine(IEnumerator routine, object owner)
|
||||
{
|
||||
m_Processor = new YieldProcessor();
|
||||
m_Owner = new WeakReference(owner);
|
||||
m_Routine = routine;
|
||||
EditorApplication.update += MoveNext;
|
||||
}
|
||||
|
||||
internal void MoveNext()
|
||||
{
|
||||
if (m_Owner != null && !m_Owner.IsAlive)
|
||||
{
|
||||
EditorApplication.update -= MoveNext;
|
||||
return;
|
||||
}
|
||||
|
||||
bool done = ProcessIEnumeratorRecursive(m_Routine);
|
||||
m_IsDone = !done;
|
||||
|
||||
if (m_IsDone)
|
||||
EditorApplication.update -= MoveNext;
|
||||
}
|
||||
|
||||
static readonly Stack<IEnumerator> kIEnumeratorProcessingStack = new Stack<IEnumerator>(32);
|
||||
private bool ProcessIEnumeratorRecursive(IEnumerator enumerator)
|
||||
{
|
||||
var root = enumerator;
|
||||
while(enumerator.Current as IEnumerator != null)
|
||||
{
|
||||
kIEnumeratorProcessingStack.Push(enumerator);
|
||||
enumerator = enumerator.Current as IEnumerator;
|
||||
}
|
||||
|
||||
//process leaf
|
||||
m_Processor.Set(enumerator.Current);
|
||||
var result = m_Processor.MoveNext(enumerator);
|
||||
|
||||
while (kIEnumeratorProcessingStack.Count > 1)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
result = kIEnumeratorProcessingStack.Pop().MoveNext();
|
||||
}
|
||||
else
|
||||
kIEnumeratorProcessingStack.Clear();
|
||||
}
|
||||
|
||||
if (kIEnumeratorProcessingStack.Count > 0 && !result && root == kIEnumeratorProcessingStack.Pop())
|
||||
{
|
||||
result = root.MoveNext();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void Stop()
|
||||
{
|
||||
m_Owner = null;
|
||||
m_Routine = null;
|
||||
EditorApplication.update -= MoveNext;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 476bd9faa78d34f40a8ecd78bcbeb5be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
public static class EditorCoroutineUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts an <see cref ="EditorCoroutine">EditorCoroutine</see> with the specified owner object.
|
||||
/// If the garbage collector collects the owner object, while the resulting coroutine is still executing, the coroutine will stop running.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// int m_Updates = 0;
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// EditorCoroutineUtility.StartCoroutine(CountEditorUpdates(), this);
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator CountEditorUpdates()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// ++m_Updates;
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="routine"> IEnumerator to iterate over. </param>
|
||||
/// <param name="owner">Object owning the coroutine. </param>
|
||||
/// <remarks>
|
||||
/// Only types that don't inherit from <see cref="UnityEngine.Object">UnityEngine.Object</see> will get collected the next time the GC runs instead of getting null-ed immediately.
|
||||
/// </remarks>
|
||||
/// <returns>A handle to an <see cref="EditorCoroutine">EditorCoroutine</see>.</returns>
|
||||
public static EditorCoroutine StartCoroutine(IEnumerator routine, object owner)
|
||||
{
|
||||
return new EditorCoroutine(routine, owner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method starts an <see cref="EditorCoroutine">EditorCoroutine</see> without an owning object. The <see cref="EditorCoroutine">EditorCoroutine</see> runs until it completes or is canceled using <see cref="StopCoroutine(EditorCoroutine)">StopCoroutine</see>.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
/// using UnityEngine;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// EditorCoroutineUtility.StartCoroutineOwnerless(LogTimeSinceStartup());
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator LogTimeSinceStartup()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// Debug.LogFormat("Time since startup: {0} s", Time.realtimeSinceStartup);
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="routine"> Generator function to execute. </param>
|
||||
/// <returns>A handle to an <see cref="EditorCoroutine">EditorCoroutine.</see></returns>
|
||||
public static EditorCoroutine StartCoroutineOwnerless(IEnumerator routine)
|
||||
{
|
||||
return new EditorCoroutine(routine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately stop an <see cref="EditorCoroutine">EditorCoroutine</see>. This method is safe to call on an already completed <see cref="EditorCoroutine">EditorCoroutine</see>.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
/// using UnityEngine;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// EditorCoroutine m_LoggerCoroutine;
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// m_LoggerCoroutine = EditorCoroutineUtility.StartCoroutineOwnerless(LogRunning());
|
||||
/// }
|
||||
///
|
||||
/// void OnDisable()
|
||||
/// {
|
||||
/// EditorCoroutineUtility.StopCoroutine(m_LoggerCoroutine);
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator LogRunning()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// Debug.Log("Running");
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="coroutine">A handle to an <see cref="EditorCoroutine">EditorCoroutine.</see></param>
|
||||
public static void StopCoroutine(EditorCoroutine coroutine)
|
||||
{
|
||||
if (coroutine == null)
|
||||
{
|
||||
Debug.LogAssertion("EditorCoroutine handle is null.");
|
||||
return;
|
||||
}
|
||||
coroutine.Stop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7e1a1ea9a4320124cab499782f159158
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
/// <summary>
|
||||
/// Suspends the <see cref="EditorCoroutine">EditorCoroutine</see> execution for the given amount of seconds, using unscaled time.
|
||||
/// The coroutine execution continues after the specified time has elapsed.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
///
|
||||
/// public class MyEditorWindow : EditorWindow
|
||||
/// {
|
||||
/// IEnumerator PrintEachSecond()
|
||||
/// {
|
||||
/// var waitForOneSecond = new EditorWaitForSeconds(1.0f);
|
||||
///
|
||||
/// while (true)
|
||||
/// {
|
||||
/// yield return waitForOneSecond;
|
||||
/// Debug.Log("Printing each second");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public class EditorWaitForSeconds
|
||||
{
|
||||
/// <summary>
|
||||
/// The time to wait in seconds.
|
||||
/// </summary>
|
||||
public float WaitTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a instruction object for yielding inside a generator function.
|
||||
/// </summary>
|
||||
/// <param name="time">The amount of time to wait in seconds.</param>
|
||||
public EditorWaitForSeconds(float time)
|
||||
{
|
||||
WaitTime = time;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 068b6a385caf5344e90c84a86136fe06
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Derived from Unity package
|
||||
* https://docs.unity3d.com/Packages/com.unity.editorcoroutines@0.0/api/Unity.EditorCoroutines.Editor.html
|
||||
*/
|
||||
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace Unity.EditorCoroutines.Editor
|
||||
namespace Meryel.UnityCodeAssist.Editor.EditorCoroutines
|
||||
{
|
||||
public static class EditorWindowCoroutineExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Start an <see cref="EditorCoroutine">EditorCoroutine</see>, owned by the calling <see cref="EditorWindow">EditorWindow</see> instance.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// this.StartCoroutine(CloseWindowDelayed());
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator CloseWindowDelayed() //close the window after 1000 frames have elapsed
|
||||
/// {
|
||||
/// int count = 1000;
|
||||
/// while (count > 0)
|
||||
/// {
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// Close();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="routine"></param>
|
||||
/// <returns></returns>
|
||||
public static EditorCoroutine StartCoroutine(this EditorWindow window, IEnumerator routine)
|
||||
{
|
||||
return new EditorCoroutine(routine, window);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately stop an <see cref="EditorCoroutine">EditorCoroutine</see> that was started by the calling <see cref="EditorWindow"/> instance. This method is safe to call on an already completed <see cref="EditorCoroutine">EditorCoroutine</see>.
|
||||
/// <code>
|
||||
/// using System.Collections;
|
||||
/// using Unity.EditorCoroutines.Editor;
|
||||
/// using UnityEditor;
|
||||
/// using UnityEngine;
|
||||
///
|
||||
/// public class ExampleWindow : EditorWindow
|
||||
/// {
|
||||
/// EditorCoroutine coroutine;
|
||||
/// void OnEnable()
|
||||
/// {
|
||||
/// coroutine = this.StartCoroutine(CloseWindowDelayed());
|
||||
/// }
|
||||
///
|
||||
/// private void OnDisable()
|
||||
/// {
|
||||
/// this.StopCoroutine(coroutine);
|
||||
/// }
|
||||
///
|
||||
/// IEnumerator CloseWindowDelayed()
|
||||
/// {
|
||||
/// while (true)
|
||||
/// {
|
||||
/// Debug.Log("Running");
|
||||
/// yield return null;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <param name="coroutine"></param>
|
||||
public static void StopCoroutine(this EditorWindow window, EditorCoroutine coroutine)
|
||||
{
|
||||
if(coroutine == null)
|
||||
{
|
||||
Debug.LogAssertion("Provided EditorCoroutine handle is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(coroutine.m_Owner == null)
|
||||
{
|
||||
Debug.LogError("The EditorCoroutine is ownerless. Please use EditorCoroutineEditor.StopCoroutine to terminate such coroutines.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!coroutine.m_Owner.IsAlive)
|
||||
return; //The EditorCoroutine's owner was already terminated execution will cease next time it is processed
|
||||
|
||||
var owner = coroutine.m_Owner.Target as EditorWindow;
|
||||
|
||||
if (owner == null || owner != null && owner != window)
|
||||
{
|
||||
Debug.LogErrorFormat("The EditorCoroutine is owned by another object: {0}.", coroutine.m_Owner.Target);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorCoroutineUtility.StopCoroutine(coroutine);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d73e3ad2af3d6c246ae57b50d3a44bc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor/ExternalReferences.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor/ExternalReferences.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c592f75bdc6ba8d41b60edd273a61b30
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/AsyncIO.dll
Normal file
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/AsyncIO.dll
Normal file
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9cbe467076181fd428865475c3ffc790
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETStandard,Version=v2.0/",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETStandard,Version=v2.0": {},
|
||||
".NETStandard,Version=v2.0/": {
|
||||
"Meryel.UnityCodeAssist.SynchronizerModel/1.1.9": {
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "2.0.3"
|
||||
},
|
||||
"runtime": {
|
||||
"Meryel.UnityCodeAssist.SynchronizerModel.dll": {}
|
||||
}
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/1.1.0": {},
|
||||
"NETStandard.Library/2.0.3": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Meryel.UnityCodeAssist.SynchronizerModel/1.1.9": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/1.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==",
|
||||
"path": "microsoft.netcore.platforms/1.1.0",
|
||||
"hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512"
|
||||
},
|
||||
"NETStandard.Library/2.0.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
|
||||
"path": "netstandard.library/2.0.3",
|
||||
"hashPath": "netstandard.library.2.0.3.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8f87de6fa268834d8e371c27af9c6a3
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e38103a6e2ae80446a9ca23ac48d9509
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,528 @@
|
|||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETStandard,Version=v2.0/",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETStandard,Version=v2.0": {},
|
||||
".NETStandard,Version=v2.0/": {
|
||||
"Meryel.UnityCodeAssist.YamlDotNet/1.0.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": "1.0.3",
|
||||
"NETStandard.Library": "2.0.3",
|
||||
"Nullable": "1.3.1",
|
||||
"System.ComponentModel.TypeConverter": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Runtime.Serialization.Formatters": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"Meryel.UnityCodeAssist.YamlDotNet.dll": {}
|
||||
}
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/1.1.0": {},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies/1.0.3": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
|
||||
}
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net461/1.0.3": {},
|
||||
"NETStandard.Library/2.0.3": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0"
|
||||
}
|
||||
},
|
||||
"Nullable/1.3.1": {},
|
||||
"System.Collections/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Collections.NonGeneric/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/System.Collections.NonGeneric.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Collections.Specialized/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Collections.NonGeneric": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Globalization.Extensions": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/System.Collections.Specialized.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.ComponentModel/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/System.ComponentModel.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.ComponentModel.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.ComponentModel": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.0/System.ComponentModel.Primitives.dll": {
|
||||
"assemblyVersion": "4.1.1.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.ComponentModel.TypeConverter/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Collections.NonGeneric": "4.3.0",
|
||||
"System.Collections.Specialized": "4.3.0",
|
||||
"System.ComponentModel": "4.3.0",
|
||||
"System.ComponentModel.Primitives": "4.3.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Linq": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Extensions": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Reflection.TypeExtensions": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Threading": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.5/System.ComponentModel.TypeConverter.dll": {
|
||||
"assemblyVersion": "4.1.1.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Debug/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Globalization.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0",
|
||||
"System.Runtime.InteropServices": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Text.Encoding": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Linq/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Diagnostics.Debug": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Extensions": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.6/System.Linq.dll": {
|
||||
"assemblyVersion": "4.1.1.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.IO": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.TypeExtensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.5/System.Reflection.TypeExtensions.dll": {
|
||||
"assemblyVersion": "4.1.1.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Globalization": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Handles/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.InteropServices/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Reflection.Primitives": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Handles": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Serialization.Formatters/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Collections": "4.3.0",
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.4/System.Runtime.Serialization.Formatters.dll": {
|
||||
"assemblyVersion": "4.0.1.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Resources.ResourceManager": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/System.Runtime.Serialization.Primitives.dll": {
|
||||
"assemblyVersion": "4.1.2.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading/4.3.0": {
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.3.0",
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard1.3/System.Threading.dll": {
|
||||
"assemblyVersion": "4.0.12.0",
|
||||
"fileVersion": "4.6.24705.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.1.0",
|
||||
"Microsoft.NETCore.Targets": "1.1.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"Meryel.UnityCodeAssist.YamlDotNet/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"Microsoft.NETCore.Platforms/1.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==",
|
||||
"path": "microsoft.netcore.platforms/1.1.0",
|
||||
"hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETCore.Targets/1.1.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==",
|
||||
"path": "microsoft.netcore.targets/1.1.0",
|
||||
"hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies/1.0.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
|
||||
"path": "microsoft.netframework.referenceassemblies/1.0.3",
|
||||
"hashPath": "microsoft.netframework.referenceassemblies.1.0.3.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies.net461/1.0.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==",
|
||||
"path": "microsoft.netframework.referenceassemblies.net461/1.0.3",
|
||||
"hashPath": "microsoft.netframework.referenceassemblies.net461.1.0.3.nupkg.sha512"
|
||||
},
|
||||
"NETStandard.Library/2.0.3": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
|
||||
"path": "netstandard.library/2.0.3",
|
||||
"hashPath": "netstandard.library.2.0.3.nupkg.sha512"
|
||||
},
|
||||
"Nullable/1.3.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Mk4ZVDfAORTjvckQprCSehi1XgOAAlk5ez06Va/acRYEloN9t6d6zpzJRn5MEq7+RnagyFIq9r+kbWzLGd+6QA==",
|
||||
"path": "nullable/1.3.1",
|
||||
"hashPath": "nullable.1.3.1.nupkg.sha512"
|
||||
},
|
||||
"System.Collections/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==",
|
||||
"path": "system.collections/4.3.0",
|
||||
"hashPath": "system.collections.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Collections.NonGeneric/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==",
|
||||
"path": "system.collections.nongeneric/4.3.0",
|
||||
"hashPath": "system.collections.nongeneric.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Collections.Specialized/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Epx8PoVZR0iuOnJJDzp7pWvdfMMOAvpUo95pC4ScH2mJuXkKA2Y4aR3cG9qt2klHgSons1WFh4kcGW7cSXvrxg==",
|
||||
"path": "system.collections.specialized/4.3.0",
|
||||
"hashPath": "system.collections.specialized.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.ComponentModel/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-VyGn1jGRZVfxnh8EdvDCi71v3bMXrsu8aYJOwoV7SNDLVhiEqwP86pPMyRGsDsxhXAm2b3o9OIqeETfN5qfezw==",
|
||||
"path": "system.componentmodel/4.3.0",
|
||||
"hashPath": "system.componentmodel.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.ComponentModel.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-j8GUkCpM8V4d4vhLIIoBLGey2Z5bCkMVNjEZseyAlm4n5arcsJOeI3zkUP+zvZgzsbLTYh4lYeP/ZD/gdIAPrw==",
|
||||
"path": "system.componentmodel.primitives/4.3.0",
|
||||
"hashPath": "system.componentmodel.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.ComponentModel.TypeConverter/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-16pQ6P+EdhcXzPiEK4kbA953Fu0MNG2ovxTZU81/qsCd1zPRsKc3uif5NgvllCY598k6bI0KUyKW8fanlfaDQg==",
|
||||
"path": "system.componentmodel.typeconverter/4.3.0",
|
||||
"hashPath": "system.componentmodel.typeconverter.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Diagnostics.Debug/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==",
|
||||
"path": "system.diagnostics.debug/4.3.0",
|
||||
"hashPath": "system.diagnostics.debug.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Globalization/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==",
|
||||
"path": "system.globalization/4.3.0",
|
||||
"hashPath": "system.globalization.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Globalization.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==",
|
||||
"path": "system.globalization.extensions/4.3.0",
|
||||
"hashPath": "system.globalization.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.IO/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==",
|
||||
"path": "system.io/4.3.0",
|
||||
"hashPath": "system.io.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Linq/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==",
|
||||
"path": "system.linq/4.3.0",
|
||||
"hashPath": "system.linq.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==",
|
||||
"path": "system.reflection/4.3.0",
|
||||
"hashPath": "system.reflection.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==",
|
||||
"path": "system.reflection.extensions/4.3.0",
|
||||
"hashPath": "system.reflection.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==",
|
||||
"path": "system.reflection.primitives/4.3.0",
|
||||
"hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Reflection.TypeExtensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==",
|
||||
"path": "system.reflection.typeextensions/4.3.0",
|
||||
"hashPath": "system.reflection.typeextensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Resources.ResourceManager/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==",
|
||||
"path": "system.resources.resourcemanager/4.3.0",
|
||||
"hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==",
|
||||
"path": "system.runtime/4.3.0",
|
||||
"hashPath": "system.runtime.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Extensions/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==",
|
||||
"path": "system.runtime.extensions/4.3.0",
|
||||
"hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Handles/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==",
|
||||
"path": "system.runtime.handles/4.3.0",
|
||||
"hashPath": "system.runtime.handles.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.InteropServices/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==",
|
||||
"path": "system.runtime.interopservices/4.3.0",
|
||||
"hashPath": "system.runtime.interopservices.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Serialization.Formatters/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-IfJxJOaVssiaLVmQqRy7GEvkwtQoYvNdVp+cTpRJTadzllivaLaX0Y0yVTRiP5Yp5kIijuuXdB5hMujpwduYcg==",
|
||||
"path": "system.runtime.serialization.formatters/4.3.0",
|
||||
"hashPath": "system.runtime.serialization.formatters.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Runtime.Serialization.Primitives/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-w6fBfup0Yq7bTpY7J6iGR150eTXGiYUGF2E/4DPyv9i3nGpVPIEzbP4w4CcFnADZGQvDSVtzHGXa3Oa5/bj48Q==",
|
||||
"path": "system.runtime.serialization.primitives/4.3.0",
|
||||
"hashPath": "system.runtime.serialization.primitives.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Text.Encoding/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==",
|
||||
"path": "system.text.encoding/4.3.0",
|
||||
"hashPath": "system.text.encoding.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==",
|
||||
"path": "system.threading/4.3.0",
|
||||
"hashPath": "system.threading.4.3.0.nupkg.sha512"
|
||||
},
|
||||
"System.Threading.Tasks/4.3.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==",
|
||||
"path": "system.threading.tasks/4.3.0",
|
||||
"hashPath": "system.threading.tasks.4.3.0.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ec866449fed6af40a047e12f31768a2
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dd04e29e638cfd84e987c860dca8fd84
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 669f868bb308d5549bba700d849bd4bb
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/NaCl.dll
Normal file
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/NaCl.dll
Normal file
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1329dcf5acec8d546bfaba8f80e94192
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/NetMQ.dll
Normal file
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/NetMQ.dll
Normal file
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a236a5ab591f120428cf934460efd4dc
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e64a643b67ae4924592c37a10a230396
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/Serilog.dll
Normal file
BIN
Assets/Plugins/CodeAssist/Editor/ExternalReferences/Serilog.dll
Normal file
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ef0d0874ba9b934d99ff6a291ad7bc1
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8d84ac9193770fa43b325cf6b810e046
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3ecc917cdff3bc1498219fd346515293
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4076d5097b2019e419e215538689454c
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b0f671a0a1784ab4c9ed3a96215a8e64
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
105
Assets/Plugins/CodeAssist/Editor/FeedbackWindow.cs
Normal file
105
Assets/Plugins/CodeAssist/Editor/FeedbackWindow.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
public class FeedbackWindow : EditorWindow
|
||||
{
|
||||
|
||||
GUIStyle? styleLabel;
|
||||
|
||||
public static void Display()
|
||||
{
|
||||
NetMQInitializer.Publisher?.SendRequestInternalLog();
|
||||
|
||||
// Get existing open window or if none, make a new one:
|
||||
var window = GetWindow<FeedbackWindow>();
|
||||
window.Show();
|
||||
|
||||
Serilog.Log.Debug("Displaying feedback window");
|
||||
|
||||
NetMQInitializer.Publisher?.SendAnalyticsEvent("Gui", "FeedbackWindow_Display");
|
||||
}
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
//**--icon
|
||||
//var icon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Sprites/Gear.png");
|
||||
//titleContent = new GUIContent("Code Assist", icon);
|
||||
titleContent = new GUIContent("Code Assist Feedback");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
var errorCount = Logger.ELogger.GetErrorCountInInternalLog();
|
||||
var warningCount = Logger.ELogger.GetWarningCountInInternalLog();
|
||||
var logContent = Logger.ELogger.GetInternalLogContent();
|
||||
if (!string.IsNullOrEmpty(Logger.ELogger.VsInternalLog))
|
||||
logContent += Logger.ELogger.VsInternalLog;
|
||||
|
||||
styleLabel ??= new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
wordWrap = true,
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
};
|
||||
|
||||
if (errorCount > 0)
|
||||
EditorGUILayout.LabelField($"{errorCount} error(s) found in logs. Please submit a feedback (via e-mail, Discord or GitHub) with the logs if possible.", styleLabel, GUILayout.ExpandWidth(true));
|
||||
else if (warningCount > 0)
|
||||
EditorGUILayout.LabelField($"{warningCount} warnings(s) found in logs. Please submit a feedback (via e-mail, Discord or GitHub) with the logs if possible.", styleLabel, GUILayout.ExpandWidth(true));
|
||||
else
|
||||
EditorGUILayout.LabelField("No errors found in logs. Please submit a feedback (via e-mail, Discord or GitHub) describing what went wrong or unexpected.", styleLabel, GUILayout.ExpandWidth(true));
|
||||
|
||||
if (GUILayout.Button("Send e-mail"))
|
||||
{
|
||||
var uri = "mailto:merryyellow@outlook.com";
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(uri));
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Send Discord message"))
|
||||
{
|
||||
//var uri = "discord://invites/2CgKHDq";
|
||||
var uri = "https://discord.gg/2CgKHDq";
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(uri));
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Submit GitHub issue"))
|
||||
{
|
||||
var uri = "https://github.com/merryyellow/Unity-Code-Assist/issues/new/choose";
|
||||
Application.OpenURL(uri);
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (GUILayout.Button("View Unity full log"))
|
||||
{
|
||||
var filePath = Logger.ELogger.FilePath;
|
||||
System.Diagnostics.Process.Start(filePath);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("View Visual Studio full log"))
|
||||
{
|
||||
var filePath = Logger.ELogger.VSFilePath;
|
||||
System.Diagnostics.Process.Start(filePath);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Copy recent logs to clipboard"))
|
||||
{
|
||||
GUIUtility.systemCopyBuffer = logContent;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Recent logs:", styleLabel, GUILayout.ExpandWidth(true));
|
||||
EditorGUILayout.SelectableLabel(logContent, EditorStyles.textArea, GUILayout.ExpandHeight(true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/FeedbackWindow.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/FeedbackWindow.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32df5c90db6b3ed4a84031cab040d4d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor/Input.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor/Input.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b0c5aeddac1e8884da485bf2a0c4d544
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
141
Assets/Plugins/CodeAssist/Editor/Input/Binary2TextExec.cs
Normal file
141
Assets/Plugins/CodeAssist/Editor/Input/Binary2TextExec.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
//namespace UTJ.UnityCommandLineTools
|
||||
namespace Meryel.UnityCodeAssist.Editor.Input
|
||||
{
|
||||
// <summary>
|
||||
// bin2textをUnityEditorから実行する為のClass
|
||||
// programed by Katsumasa.Kimura
|
||||
// </summary>
|
||||
public class Binary2TextExec : EditorToolExec
|
||||
{
|
||||
public Binary2TextExec() : base("binary2text") { }
|
||||
|
||||
// <summary>
|
||||
// bin2text filePath outPath options
|
||||
// /summary>
|
||||
public int Exec(string filePath, string outPath, string options)
|
||||
{
|
||||
var args = string.Format(@"""{0}"" ""{1}"" {2}", filePath, outPath, options);
|
||||
return Exec(args);
|
||||
}
|
||||
|
||||
public int Exec(string filePath, string outPath, bool detailed = false, bool largeBinaryHashOnly = false, bool hexFloat = false)
|
||||
{
|
||||
//var args = string.Format(@"""{0}"" ""{1}"" {2}", filePath, outPath, options);
|
||||
var args = string.Format(@"""{0}"" ""{1}""", filePath, outPath);
|
||||
|
||||
if (detailed)
|
||||
args += " -detailed";
|
||||
if (largeBinaryHashOnly)
|
||||
args += " -largebinaryhashonly";
|
||||
if (hexFloat)
|
||||
args += " -hexfloat";
|
||||
|
||||
return Exec(args);
|
||||
}
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// UnityEditorに含まれるコマンドラインツールを実行する為の基底Class
|
||||
// programed by Katsumasa.Kimura
|
||||
//</summary>
|
||||
public class EditorToolExec
|
||||
{
|
||||
// <value>
|
||||
// UnityEditorがインストールされているディレクトリへのパス
|
||||
// </value>
|
||||
protected string mEditorPath;
|
||||
|
||||
// <value>
|
||||
// Toolsディレクトリへのパス
|
||||
// </value>
|
||||
protected string mToolsPath;
|
||||
|
||||
// <value>
|
||||
// 実行ファイル名
|
||||
// </value>
|
||||
protected string mExecFname;
|
||||
|
||||
// <value>
|
||||
// 実行ファイルへのフルパス
|
||||
// </value>
|
||||
protected string mExecFullPath;
|
||||
|
||||
// <value>
|
||||
// 実行結果のOUTPUT
|
||||
// </value>
|
||||
private string? mOutput;
|
||||
|
||||
// <value>
|
||||
// 実行結果のOUTPUT
|
||||
// </value>
|
||||
public string? Output
|
||||
{
|
||||
get { return mOutput; }
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// コンストラクタ
|
||||
// <param>
|
||||
// mExecFname : 実行ファイル名
|
||||
// </param>
|
||||
// /summary>
|
||||
public EditorToolExec(string mExecFname)
|
||||
{
|
||||
mEditorPath = Path.GetDirectoryName(EditorApplication.applicationPath);
|
||||
mToolsPath = Path.Combine(mEditorPath, @"Data/Tools");
|
||||
this.mExecFname = mExecFname;
|
||||
//var files = Directory.GetFiles(mToolsPath, mExecFname, SearchOption.AllDirectories);
|
||||
var files = Directory.GetFiles(mEditorPath, mExecFname + "*", SearchOption.AllDirectories);
|
||||
|
||||
if (files.Length == 0)
|
||||
Serilog.Log.Error("{App} app couldn't be found at {Path}", mExecFname, mEditorPath);
|
||||
|
||||
mExecFullPath = files[0];
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// コマンドラインツールを実行する
|
||||
// <param>
|
||||
// arg : コマンドラインツールに渡す引数
|
||||
// </param>
|
||||
// </summary>
|
||||
public int Exec(string arg)
|
||||
{
|
||||
int exitCode = -1;
|
||||
|
||||
try
|
||||
{
|
||||
using var process = new Process();
|
||||
process.StartInfo.FileName = mExecFullPath;
|
||||
process.StartInfo.Arguments = arg;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.Start();
|
||||
mOutput = process.StandardOutput.ReadToEnd();
|
||||
process.WaitForExit();
|
||||
exitCode = process.ExitCode;
|
||||
process.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//UnityEngine.Debug.Log(e);
|
||||
Serilog.Log.Error(e, "Exception while running process at {Scope}.{Location}", nameof(EditorToolExec), nameof(Exec));
|
||||
}
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6db78598a7c20a141975035612031328
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
111
Assets/Plugins/CodeAssist/Editor/Input/InputManagerMonitor.cs
Normal file
111
Assets/Plugins/CodeAssist/Editor/Input/InputManagerMonitor.cs
Normal file
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Input
|
||||
{
|
||||
|
||||
public class InputManagerMonitor
|
||||
{
|
||||
private static readonly Lazy<InputManagerMonitor> _instance = new Lazy<InputManagerMonitor>(() => new InputManagerMonitor());
|
||||
public static InputManagerMonitor Instance => _instance.Value;
|
||||
|
||||
//UnityInputManager inputManager;
|
||||
readonly string inputManagerFilePath;
|
||||
DateTime previousTagManagerLastWrite;
|
||||
|
||||
public InputManagerMonitor()
|
||||
{
|
||||
EditorApplication.update += Update;
|
||||
inputManagerFilePath = CommonTools.GetInputManagerFilePath();
|
||||
|
||||
previousTagManagerLastWrite = System.IO.File.GetLastWriteTime(inputManagerFilePath);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var currentInputManagerLastWrite = System.IO.File.GetLastWriteTime(inputManagerFilePath);
|
||||
if (currentInputManagerLastWrite != previousTagManagerLastWrite)
|
||||
{
|
||||
previousTagManagerLastWrite = currentInputManagerLastWrite;
|
||||
Bump();
|
||||
}
|
||||
}
|
||||
|
||||
public void Bump()
|
||||
{
|
||||
Serilog.Log.Debug("InputMonitor {Event}", nameof(Bump));
|
||||
|
||||
var inputManager = new UnityInputManager();
|
||||
inputManager.ReadFromPath(inputManagerFilePath);
|
||||
inputManager.SendData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static partial class Extensions
|
||||
{
|
||||
public static string GetInfo(this List<InputAxis> axes, string? name)
|
||||
{
|
||||
if (name == null || string.IsNullOrEmpty(name))
|
||||
return string.Empty;
|
||||
|
||||
//axis.descriptiveName
|
||||
var axesWithName = axes.Where(a => a.Name == name);
|
||||
|
||||
int threshold = 80;
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
|
||||
foreach (var axis in axesWithName)
|
||||
if (!string.IsNullOrEmpty(axis.descriptiveName))
|
||||
sb.Append($"{axis.descriptiveName} ");
|
||||
|
||||
if (sb.Length > threshold)
|
||||
return sb.ToString();
|
||||
|
||||
foreach (var axis in axesWithName)
|
||||
if (!string.IsNullOrEmpty(axis.descriptiveNegativeName))
|
||||
sb.Append($"{axis.descriptiveNegativeName} ");
|
||||
|
||||
if (sb.Length > threshold)
|
||||
return sb.ToString();
|
||||
|
||||
foreach (var axis in axesWithName)
|
||||
if (!string.IsNullOrEmpty(axis.positiveButton))
|
||||
sb.Append($"[{axis.positiveButton}] ");
|
||||
|
||||
if (sb.Length > threshold)
|
||||
return sb.ToString();
|
||||
|
||||
foreach (var axis in axesWithName)
|
||||
if (!string.IsNullOrEmpty(axis.altPositiveButton))
|
||||
sb.Append($"{{{axis.altPositiveButton}}} ");
|
||||
|
||||
if (sb.Length > threshold)
|
||||
return sb.ToString();
|
||||
|
||||
foreach (var axis in axesWithName)
|
||||
if (!string.IsNullOrEmpty(axis.negativeButton))
|
||||
sb.Append($"-[{axis.negativeButton}] ");
|
||||
|
||||
if (sb.Length > threshold)
|
||||
return sb.ToString();
|
||||
|
||||
foreach (var axis in axesWithName)
|
||||
if (!string.IsNullOrEmpty(axis.altNegativeButton))
|
||||
sb.Append($"-{{{axis.altNegativeButton}}} ");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: abc0210fcf4b7cb46baab11d1db6fdb0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
210
Assets/Plugins/CodeAssist/Editor/Input/Text2Yaml.cs
Normal file
210
Assets/Plugins/CodeAssist/Editor/Input/Text2Yaml.cs
Normal file
|
@ -0,0 +1,210 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Input
|
||||
{
|
||||
|
||||
public class Text2Yaml
|
||||
{
|
||||
public static string Convert(IEnumerable<string> textLines)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var stack = new Stack<(string typeName, string identifier, int indentation)>();
|
||||
|
||||
sb.AppendLine(@"%YAML 1.1");
|
||||
sb.AppendLine(@"%TAG !u! tag:unity3d.com,2011:");
|
||||
sb.AppendLine(@"--- !u!13 &1");
|
||||
sb.AppendLine(@"InputManager:");
|
||||
|
||||
var regexIndentation = new Regex("^\\s*");
|
||||
|
||||
var regexString = new Regex("^(\\s+)(\\w+)\\s+\"([a-zA-Z0-9_ ]*)\"\\s+\\(string\\)$");
|
||||
var regexValue = new Regex("^(\\s+)(\\w+)\\s+(-?[0-9.]*)\\s+\\(((bool)|(int)|(float)|(unsigned int))\\)$");
|
||||
var regexType = new Regex("^(\\s+)(\\w+)\\s+\\((\\w+)\\)$");
|
||||
|
||||
var regexVectorSize = new Regex("(\\s+)size\\s+(\\d)+\\s+\\(int\\)");
|
||||
//var regexVectorData = new Regex("(\\s+)data \\(InputAxis\\)"); // remove InputAxis to make it more generic
|
||||
|
||||
string curTextLine;
|
||||
var curTextLineNo = 3;
|
||||
var textIndentation = 1;
|
||||
var indentationPrefix = new string(' ', textIndentation * 2);
|
||||
stack.Push(("InputManager", "InputManager", textIndentation));
|
||||
|
||||
|
||||
foreach (var line in textLines.Skip(4))
|
||||
{
|
||||
curTextLine = line;
|
||||
curTextLineNo++;
|
||||
|
||||
|
||||
// Skip empty lines
|
||||
if (line.Length == 0)
|
||||
continue;
|
||||
|
||||
// Check if type undeclared, scope goes down, indentation decrements
|
||||
{
|
||||
var indentationMatch = regexIndentation.Match(line);
|
||||
if (indentationMatch.Success)
|
||||
{
|
||||
var indentation = indentationMatch.Groups[0].Value.Length;
|
||||
|
||||
if (indentation > textIndentation)
|
||||
Error($"indentation({indentation}) > textIndentation({textIndentation})");
|
||||
|
||||
while (indentation < textIndentation)
|
||||
{
|
||||
stack.Pop();
|
||||
textIndentation--;
|
||||
var typeIndentation = textIndentation;
|
||||
if (stack.TryPeek(out var curType2))
|
||||
typeIndentation = curType2.indentation;
|
||||
else if (line.Length > 0)
|
||||
Error("stack empty at type undeclaration");
|
||||
indentationPrefix = new string(' ', typeIndentation * 2);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Error($"{nameof(regexIndentation)} failed");
|
||||
}
|
||||
}
|
||||
|
||||
// Skip size field of vectors
|
||||
if (stack.TryPeek(out var curType1) && curType1.typeName == "vector")
|
||||
{
|
||||
var vectorSizeMatch = regexVectorSize.Match(line);
|
||||
if (vectorSizeMatch.Success)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Read string fields
|
||||
{
|
||||
var stringMatch = regexString.Match(line);
|
||||
if (stringMatch.Success)
|
||||
{
|
||||
AddLine(stringMatch.Groups[2] + ": " + stringMatch.Groups[3]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Read bool/int/float/unsignedInt fields
|
||||
{
|
||||
var valueMatch = regexValue.Match(line);
|
||||
if (valueMatch.Success)
|
||||
{
|
||||
AddLine(valueMatch.Groups[2] + ": " + valueMatch.Groups[3]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if new type declared, scope goes up, indentation increases
|
||||
{
|
||||
var typeMatch = regexType.Match(line);
|
||||
if (typeMatch.Success)
|
||||
{
|
||||
var identifier = typeMatch.Groups[2].Value;
|
||||
var typeName = typeMatch.Groups[3].Value;
|
||||
|
||||
var isVectorData = false;
|
||||
if (stack.TryPeek(out var curType2) && curType2.typeName == "vector" && identifier == "data")
|
||||
isVectorData = true;
|
||||
|
||||
var typeIndentation = textIndentation;
|
||||
if (stack.TryPeek(out var curType3))
|
||||
typeIndentation = curType3.indentation;
|
||||
else if (line.Length > 0)
|
||||
Error("stack empty at type declaration");
|
||||
|
||||
if (!isVectorData)
|
||||
{
|
||||
AddLine(typeMatch.Groups[2] + ":");
|
||||
}
|
||||
else
|
||||
{
|
||||
var customIndentation = typeIndentation - 1;
|
||||
if (customIndentation < 0)
|
||||
Error($"customIndentation({customIndentation}) < 0");
|
||||
var customIndentationPrefix = new string(' ', customIndentation * 2);
|
||||
AddLine("- serializedVersion: 3", customIndentationPrefix);
|
||||
}
|
||||
|
||||
|
||||
textIndentation++;
|
||||
typeIndentation++;
|
||||
|
||||
if (isVectorData)
|
||||
typeIndentation--;
|
||||
|
||||
stack.Push((typeName, identifier, typeIndentation));
|
||||
indentationPrefix = new string(' ', typeIndentation * 2);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Error("line failed to match all cases");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return sb.ToString();
|
||||
|
||||
|
||||
void AddLine(string line, string? customIndentationPrefix = null)
|
||||
{
|
||||
string suffix;
|
||||
if (stack.TryPeek(out var top))
|
||||
suffix = $" # {textIndentation}, {top.indentation}, {top.typeName} {top.identifier}";
|
||||
else
|
||||
suffix = $" # {textIndentation}, nil";
|
||||
|
||||
if (customIndentationPrefix != null)
|
||||
sb.AppendLine(customIndentationPrefix + line + suffix);
|
||||
else
|
||||
sb.AppendLine(indentationPrefix + line + suffix);
|
||||
}
|
||||
|
||||
void Error(string message)
|
||||
{
|
||||
var errorMessage = $"Text2Yaml error '{message}' at lineNo: {curTextLineNo}, line: '{curTextLine}' at {Environment.StackTrace}";
|
||||
//throw new Exception(errorMessage);
|
||||
Serilog.Log.Warning(errorMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static partial class Extensions
|
||||
{
|
||||
public static bool TryPeek<T>(this Stack<T> stack, /*[MaybeNullWhen(false)]*/ out T result)
|
||||
{
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
result = stack.Peek();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = default!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Input/Text2Yaml.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Input/Text2Yaml.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d662105b3c16a894aa31647bdbd740ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
405
Assets/Plugins/CodeAssist/Editor/Input/UnityInputManager.cs
Normal file
405
Assets/Plugins/CodeAssist/Editor/Input/UnityInputManager.cs
Normal file
|
@ -0,0 +1,405 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Input
|
||||
{
|
||||
|
||||
|
||||
internal class UnityInputManager
|
||||
{
|
||||
//string yamlPath;
|
||||
TextReader? reader;
|
||||
InputManager? inputManager;
|
||||
|
||||
public void ReadFromText(string text)
|
||||
{
|
||||
reader = new StringReader(text);
|
||||
ReadAux(false, out _);
|
||||
}
|
||||
|
||||
public void ReadFromPath(string yamlPath)
|
||||
{
|
||||
|
||||
switch (UnityEditor.EditorSettings.serializationMode)
|
||||
{
|
||||
case UnityEditor.SerializationMode.ForceText:
|
||||
{
|
||||
reader = new StreamReader(yamlPath);
|
||||
ReadAux(false, out _);
|
||||
}
|
||||
break;
|
||||
|
||||
case UnityEditor.SerializationMode.ForceBinary:
|
||||
{
|
||||
// this approach will work for InputManager since its file size is small and limited
|
||||
// but in the future, we may need to switch to reading binary files for big files
|
||||
// like this https://github.com/Unity-Technologies/UnityDataTools
|
||||
// or this https://github.com/SeriousCache/UABE
|
||||
var converted = GetOrCreateConvertedFile(yamlPath);
|
||||
if (!File.Exists(converted))
|
||||
{
|
||||
Serilog.Log.Warning("Temp file {TempFile} couldn't found for converted yaml input file. Auto Input Manager will not work!", converted);
|
||||
return;
|
||||
}
|
||||
var rawLines = File.ReadLines(converted);
|
||||
var yamlText = Text2Yaml.Convert(rawLines);
|
||||
reader = new StringReader(yamlText);
|
||||
ReadAux(false, out _);
|
||||
}
|
||||
break;
|
||||
|
||||
case UnityEditor.SerializationMode.Mixed:
|
||||
{
|
||||
reader = new StreamReader(yamlPath);
|
||||
ReadAux(true, out var hasSemanticError);
|
||||
if (hasSemanticError)
|
||||
{
|
||||
var converted = GetOrCreateConvertedFile(yamlPath);
|
||||
if (!File.Exists(converted))
|
||||
{
|
||||
Serilog.Log.Warning("Temp file {TempFile} couldn't found for converted yaml input file. Auto Input Manager will not work!", converted);
|
||||
return;
|
||||
}
|
||||
var rawLines = File.ReadLines(converted);
|
||||
var yamlText = Text2Yaml.Convert(rawLines);
|
||||
reader = new StringReader(yamlText);
|
||||
ReadAux(false, out _);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ReadAux(bool canHaveSemanticError, out bool hasSemanticError)
|
||||
{
|
||||
hasSemanticError = false;
|
||||
|
||||
if (reader == null)
|
||||
{
|
||||
Serilog.Log.Warning($"{nameof(UnityInputManager)}.{nameof(reader)} is null");
|
||||
return;
|
||||
}
|
||||
|
||||
//var reader = new StreamReader(yamlPath);
|
||||
var deserializer = new YamlDotNet.Serialization.DeserializerBuilder()
|
||||
.WithTagMapping("tag:unity3d.com,2011:13", typeof(Class13Mapper))
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
//serializer.Settings.RegisterTagMapping("tag:unity3d.com,2011:13", typeof(Class13));
|
||||
//serializer.Settings.ComparerForKeySorting = null;
|
||||
Class13Mapper? result;
|
||||
try
|
||||
{
|
||||
result = deserializer.Deserialize<Class13Mapper>(reader);
|
||||
}
|
||||
catch (YamlDotNet.Core.SemanticErrorException semanticErrorException)
|
||||
{
|
||||
Serilog.Log.Debug(semanticErrorException, "Couldn't parse InputManager.asset yaml file");
|
||||
if (!canHaveSemanticError)
|
||||
Serilog.Log.Error(semanticErrorException, "Couldn't parse InputManager.asset yaml file unexpectedly");
|
||||
|
||||
hasSemanticError = true;
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Close();
|
||||
}
|
||||
|
||||
var inputManagerMapper = result?.InputManager;
|
||||
if (inputManagerMapper == null)
|
||||
{
|
||||
Serilog.Log.Warning($"{nameof(inputManagerMapper)} is null");
|
||||
return;
|
||||
}
|
||||
|
||||
inputManager = new InputManager(inputManagerMapper);
|
||||
}
|
||||
|
||||
|
||||
public void SendData()
|
||||
{
|
||||
if (inputManager == null)
|
||||
return;
|
||||
|
||||
var axisNames = inputManager.Axes.Select(a => a.Name!).Where(n => !string.IsNullOrEmpty(n)).Distinct().ToArray();
|
||||
var axisInfos = axisNames.Select(a => inputManager.Axes.GetInfo(a)).ToArray();
|
||||
if (!CreateBindingsMap(out var buttonKeys, out var buttonAxis))
|
||||
return;
|
||||
|
||||
string[] joystickNames;
|
||||
try
|
||||
{
|
||||
joystickNames = UnityEngine.Input.GetJoystickNames();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Occurs if user have switched active Input handling to Input System package in Player Settings.
|
||||
joystickNames = new string[0];
|
||||
}
|
||||
|
||||
NetMQInitializer.Publisher?.SendInputManager(axisNames, axisInfos, buttonKeys, buttonAxis, joystickNames);
|
||||
|
||||
/*
|
||||
NetMQInitializer.Publisher?.SendInputManager(
|
||||
inputManager.Axes.Select(a => a.Name).Distinct().ToArray(),
|
||||
inputManager.Axes.Select(a => a.positiveButton).ToArray(),
|
||||
inputManager.Axes.Select(a => a.negativeButton).ToArray(),
|
||||
inputManager.Axes.Select(a => a.altPositiveButton).ToArray(),
|
||||
inputManager.Axes.Select(a => a.altNegativeButton).ToArray(),
|
||||
UnityEngine.Input.GetJoystickNames()
|
||||
);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool CreateBindingsMap([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string[]? inputKeys, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string[]? inputAxis)
|
||||
{
|
||||
if (inputManager == null)
|
||||
{
|
||||
inputKeys = null;
|
||||
inputAxis = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var dict = new Dictionary<string, string?>();
|
||||
|
||||
foreach (var axis in inputManager.Axes)
|
||||
{
|
||||
if (axis.altNegativeButton != null && !string.IsNullOrEmpty(axis.altNegativeButton))
|
||||
dict[axis.altNegativeButton] = axis.Name;
|
||||
}
|
||||
foreach (var axis in inputManager.Axes)
|
||||
{
|
||||
if (axis.negativeButton != null && !string.IsNullOrEmpty(axis.negativeButton))
|
||||
dict[axis.negativeButton] = axis.Name;
|
||||
}
|
||||
foreach (var axis in inputManager.Axes)
|
||||
{
|
||||
if (axis.altPositiveButton != null && !string.IsNullOrEmpty(axis.altPositiveButton))
|
||||
dict[axis.altPositiveButton] = axis.Name;
|
||||
}
|
||||
foreach (var axis in inputManager.Axes)
|
||||
{
|
||||
if (axis.positiveButton != null && !string.IsNullOrEmpty(axis.positiveButton))
|
||||
dict[axis.positiveButton] = axis.Name;
|
||||
}
|
||||
|
||||
var keys = new string[dict.Count];
|
||||
var values = new string[dict.Count];
|
||||
dict.Keys.CopyTo(keys, 0);
|
||||
dict.Values.CopyTo(values, 0);
|
||||
|
||||
inputKeys = keys;
|
||||
inputAxis = values;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static string GetOrCreateConvertedFile(string filePath)
|
||||
{
|
||||
var hash = GetMD5Hash(filePath);
|
||||
var convertedPath = Path.Combine(Path.GetTempPath(), $"UCA_IM_{hash}.txt");
|
||||
|
||||
if (!File.Exists(convertedPath))
|
||||
{
|
||||
Serilog.Log.Debug("Converting binary to text format of {File} to {Target}", filePath, convertedPath);
|
||||
var converter = new Binary2TextExec();
|
||||
converter.Exec(filePath, convertedPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Debug("Converted file already exists at {Target}", convertedPath);
|
||||
}
|
||||
|
||||
return convertedPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hash of the file using MD5.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMD5Hash(string filePath)
|
||||
{
|
||||
using var md5 = new MD5CryptoServiceProvider();
|
||||
return GetHash(filePath, md5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hash of the file using MD5.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMD5Hash(Stream s)
|
||||
{
|
||||
using var md5 = new MD5CryptoServiceProvider();
|
||||
return GetHash(s, md5);
|
||||
}
|
||||
|
||||
private static string GetHash(string filePath, HashAlgorithm hasher)
|
||||
{
|
||||
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
return GetHash(fs, hasher);
|
||||
}
|
||||
|
||||
private static string GetHash(Stream s, HashAlgorithm hasher)
|
||||
{
|
||||
var hash = hasher.ComputeHash(s);
|
||||
var hashStr = Convert.ToBase64String(hash);
|
||||
//return hashStr.TrimEnd('=');
|
||||
var hashStrAlphaNumeric = System.Text.RegularExpressions.Regex.Replace(hashStr, "[^A-Za-z0-9]", "");
|
||||
return hashStrAlphaNumeric;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum AxisType
|
||||
{
|
||||
KeyOrMouseButton = 0,
|
||||
MouseMovement = 1,
|
||||
JoystickAxis = 2
|
||||
};
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
|
||||
public class InputAxisMapper
|
||||
{
|
||||
public int serializedVersion { get; set; }
|
||||
|
||||
public string? m_Name { get; set; }
|
||||
public string? descriptiveName { get; set; }
|
||||
public string? descriptiveNegativeName { get; set; }
|
||||
public string? negativeButton { get; set; }
|
||||
public string? positiveButton { get; set; }
|
||||
public string? altNegativeButton { get; set; }
|
||||
public string? altPositiveButton { get; set; }
|
||||
|
||||
//public float gravity { get; set; }
|
||||
//public float dead { get; set; }
|
||||
//public float sensitivity { get; set; }
|
||||
public string? gravity { get; set; }
|
||||
public string? dead { get; set; }
|
||||
public string? sensitivity { get; set; }
|
||||
|
||||
//public bool snap { get; set; }
|
||||
public int snap { get; set; }
|
||||
//public bool invert { get; set; }
|
||||
public int invert { get; set; }
|
||||
|
||||
//public AxisType type { get; set; }
|
||||
public int type { get; set; }
|
||||
|
||||
public int axis { get; set; }
|
||||
public int joyNum { get; set; }
|
||||
}
|
||||
|
||||
public class InputAxis
|
||||
{
|
||||
readonly InputAxisMapper map;
|
||||
|
||||
public InputAxis(InputAxisMapper map)
|
||||
{
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public int SerializedVersion
|
||||
{
|
||||
get { return map.serializedVersion; }
|
||||
set { map.serializedVersion = value; }
|
||||
}
|
||||
|
||||
public string? Name => map.m_Name;
|
||||
public string? descriptiveName => map.descriptiveName;
|
||||
public string? descriptiveNegativeName => map.descriptiveNegativeName;
|
||||
public string? negativeButton => map.negativeButton;
|
||||
public string? positiveButton => map.positiveButton;
|
||||
public string? altNegativeButton => map.altNegativeButton;
|
||||
public string? altPositiveButton => map.altPositiveButton;
|
||||
|
||||
public float gravity => float.Parse(map.gravity);//**--format
|
||||
public float dead => float.Parse(map.dead);//**--format
|
||||
public float sensitivity => float.Parse(map.sensitivity);//**--format
|
||||
|
||||
public bool snap => map.snap != 0;
|
||||
public bool invert => map.invert != 0;
|
||||
|
||||
public AxisType type => (AxisType)map.type;
|
||||
|
||||
public int axis => map.axis;
|
||||
public int joyNum => map.joyNum;
|
||||
}
|
||||
|
||||
public class InputManagerMapper
|
||||
{
|
||||
public int m_ObjectHideFlags { get; set; }
|
||||
public int serializedVersion { get; set; }
|
||||
public int m_UsePhysicalKeys { get; set; }
|
||||
public List<InputAxisMapper>? m_Axes { get; set; }
|
||||
}
|
||||
|
||||
#pragma warning restore IDE1006
|
||||
|
||||
public class InputManager
|
||||
{
|
||||
readonly InputManagerMapper map;
|
||||
readonly List<InputAxis> axes;
|
||||
|
||||
public InputManager(InputManagerMapper map)
|
||||
{
|
||||
this.map = map;
|
||||
this.axes = new List<InputAxis>();
|
||||
|
||||
if (map.m_Axes == null)
|
||||
{
|
||||
Serilog.Log.Warning($"map.m_Axes is null");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var a in map.m_Axes)
|
||||
this.axes.Add(new InputAxis(a));
|
||||
}
|
||||
|
||||
public int ObjectHideFlags
|
||||
{
|
||||
get { return map.m_ObjectHideFlags; }
|
||||
set { map.m_ObjectHideFlags = value; }
|
||||
}
|
||||
|
||||
public int SerializedVersion
|
||||
{
|
||||
get { return map.serializedVersion; }
|
||||
set { map.serializedVersion = value; }
|
||||
}
|
||||
|
||||
public bool UsePhysicalKeys
|
||||
{
|
||||
get { return map.m_UsePhysicalKeys != 0; }
|
||||
set { map.m_UsePhysicalKeys = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
/*public List<InputAxisMapper> Axes
|
||||
{
|
||||
get { return map.m_Axes; }
|
||||
set { map.m_Axes = value; }
|
||||
}*/
|
||||
public List<InputAxis> Axes => axes;
|
||||
}
|
||||
|
||||
public class Class13Mapper
|
||||
{
|
||||
public InputManagerMapper? InputManager { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 94bc173b04900674ba9cf4b722f8f8d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor/Logger.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor/Logger.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 33adb743cc8450b4c8a6105599c145be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
22
Assets/Plugins/CodeAssist/Editor/Logger/Attributes.cs
Normal file
22
Assets/Plugins/CodeAssist/Editor/Logger/Attributes.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
#if !NET_UNITY_4_8
|
||||
namespace System.Diagnostics.CodeAnalysis
|
||||
{
|
||||
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
|
||||
internal sealed class NotNullWhenAttribute : Attribute
|
||||
{
|
||||
/// <summary>Initializes the attribute with the specified return value condition.</summary>
|
||||
/// <param name="returnValue">
|
||||
/// The return value condition. If the method returns this value, the associated parameter will not be null.
|
||||
/// </param>
|
||||
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
|
||||
|
||||
/// <summary>Gets the return value condition.</summary>
|
||||
public bool ReturnValue { get; }
|
||||
}
|
||||
}
|
||||
#endif
|
11
Assets/Plugins/CodeAssist/Editor/Logger/Attributes.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Logger/Attributes.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eebe08ae528d7724887b8d74bd2a5551
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
115
Assets/Plugins/CodeAssist/Editor/Logger/CommonTools.cs
Normal file
115
Assets/Plugins/CodeAssist/Editor/Logger/CommonTools.cs
Normal file
|
@ -0,0 +1,115 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using static System.IO.Path;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
public static class CommonTools
|
||||
{
|
||||
public static string GetTagManagerFilePath()
|
||||
{
|
||||
var projectPath = GetProjectPathRaw();
|
||||
var tagManagerPath = Combine(projectPath, "ProjectSettings/TagManager.asset");
|
||||
return tagManagerPath;
|
||||
}
|
||||
|
||||
public static string GetInputManagerFilePath()
|
||||
{
|
||||
var projectPath = GetProjectPathRaw();
|
||||
var inputManagerPath = Combine(projectPath, "ProjectSettings/InputManager.asset");
|
||||
return inputManagerPath;
|
||||
}
|
||||
|
||||
public static string GetProjectPath()
|
||||
{
|
||||
var rawPath = GetProjectPathRaw();
|
||||
var osPath = new OSPath(rawPath);
|
||||
var unixPath = osPath.Unix;
|
||||
var trimmed = unixPath.TrimEnd('\\', '/');
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the path to the project folder.
|
||||
/// </summary>
|
||||
/// <returns>The project folder path</returns>
|
||||
static string GetProjectPathRaw()
|
||||
{
|
||||
// Application.dataPath returns the path including /Assets, which we need to strip off
|
||||
var path = UnityEngine.Application.dataPath;
|
||||
var directory = new DirectoryInfo(path);
|
||||
var parent = directory.Parent;
|
||||
if (parent != null)
|
||||
return parent.FullName;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static int GetHashOfPath(string path)
|
||||
{
|
||||
var osPath = new OSPath(path);
|
||||
var unixPath = osPath.Unix;
|
||||
var trimmed = unixPath.TrimEnd('\\', '/');
|
||||
var hash = trimmed.GetHashCode();
|
||||
|
||||
if (hash < 0) // Get rid of the negative values, so there will be no '-' char in file names
|
||||
{
|
||||
hash++;
|
||||
hash = Math.Abs(hash);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/dmitrynogin/cdsf/blob/master/Cds.Folders/OSPath.cs
|
||||
internal class OSPath
|
||||
{
|
||||
public static readonly OSPath Empty = "";
|
||||
|
||||
public static bool IsWindows => DirectorySeparatorChar == '\\';
|
||||
|
||||
public OSPath(string text)
|
||||
{
|
||||
Text = text.Trim();
|
||||
}
|
||||
|
||||
public static implicit operator OSPath(string text) => new OSPath(text);
|
||||
public static implicit operator string(OSPath path) => path.Normalized;
|
||||
public override string ToString() => Normalized;
|
||||
|
||||
protected string Text { get; }
|
||||
|
||||
public string Normalized => IsWindows ? Windows : Unix;
|
||||
public string Windows => Text.Replace('/', '\\');
|
||||
//public string Unix => Simplified.Text.Replace('\\', '/');
|
||||
public string Unix => Text.Replace('\\', '/');
|
||||
|
||||
public OSPath Relative => Simplified.Text.TrimStart('/', '\\');
|
||||
public OSPath Absolute => IsAbsolute ? this : "/" + Relative;
|
||||
|
||||
public bool IsAbsolute => IsRooted || HasVolume;
|
||||
public bool IsRooted => Text.Length >= 1 && (Text[0] == '/' || Text[0] == '\\');
|
||||
public bool HasVolume => Text.Length >= 2 && Text[1] == ':';
|
||||
public OSPath Simplified => HasVolume ? Text.Substring(2) : Text;
|
||||
|
||||
public OSPath Parent => GetDirectoryName(Text);
|
||||
|
||||
public bool Contains(OSPath path) =>
|
||||
Normalized.StartsWith(path);
|
||||
|
||||
public static OSPath operator +(OSPath left, OSPath right) =>
|
||||
new OSPath(Combine(left, right.Relative));
|
||||
|
||||
public static OSPath operator -(OSPath left, OSPath right) =>
|
||||
left.Contains(right)
|
||||
? new OSPath(left.Normalized.Substring(right.Normalized.Length)).Relative
|
||||
: left;
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Logger/CommonTools.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Logger/CommonTools.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cb6ae855b8059214095179e3a316467b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
using Serilog.Configuration;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Logger
|
||||
{
|
||||
public class DomainHashEnricher : ILogEventEnricher
|
||||
{
|
||||
static readonly int domainHash;
|
||||
|
||||
static DomainHashEnricher()
|
||||
{
|
||||
var guid = UnityEditor.GUID.Generate();
|
||||
domainHash = guid.GetHashCode();
|
||||
}
|
||||
|
||||
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
|
||||
{
|
||||
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty(
|
||||
"DomainHash", domainHash));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d1235c7b5b457d848833746026792ef7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
186
Assets/Plugins/CodeAssist/Editor/Logger/ELogger.cs
Normal file
186
Assets/Plugins/CodeAssist/Editor/Logger/ELogger.cs
Normal file
|
@ -0,0 +1,186 @@
|
|||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Logger
|
||||
{
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class ELogger
|
||||
{
|
||||
public static event System.Action? OnVsInternalLogChanged;
|
||||
|
||||
|
||||
// Change 'new LoggerConfiguration().MinimumLevel.Debug();' if you change these values
|
||||
const Serilog.Events.LogEventLevel fileMinLevel = Serilog.Events.LogEventLevel.Debug;
|
||||
const Serilog.Events.LogEventLevel outputWindowMinLevel = Serilog.Events.LogEventLevel.Information;
|
||||
static LoggingLevelSwitch? fileLevelSwitch, outputWindowLevelSwitch;
|
||||
|
||||
//static bool IsInitialized { get; set; }
|
||||
|
||||
static ILogEventSink? _outputWindowSink;
|
||||
static ILogEventSink? _memorySink;
|
||||
|
||||
|
||||
public static string GetInternalLogContent() => _memorySink == null ? string.Empty : ((MemorySink)_memorySink).Export();
|
||||
public static int GetErrorCountInInternalLog() => _memorySink == null ? 0 : ((MemorySink)_memorySink).ErrorCount;
|
||||
public static int GetWarningCountInInternalLog() => _memorySink == null ? 0 : ((MemorySink)_memorySink).WarningCount;
|
||||
|
||||
public static string? FilePath { get; private set; }
|
||||
public static string? VSFilePath { get; private set; }
|
||||
|
||||
//**-- make it work with multiple clients
|
||||
static string? _vsInternalLog;
|
||||
public static string? VsInternalLog
|
||||
{
|
||||
get => _vsInternalLog;
|
||||
set
|
||||
{
|
||||
_vsInternalLog = value;
|
||||
OnVsInternalLogChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ELogger()
|
||||
{
|
||||
var isFirst = false;
|
||||
const string stateName = "isFirst";
|
||||
if (!SessionState.GetBool(stateName, false))
|
||||
{
|
||||
isFirst = true;
|
||||
SessionState.SetBool(stateName, true);
|
||||
}
|
||||
|
||||
var projectPath = CommonTools.GetProjectPath();
|
||||
var outputWindowSink = new System.Lazy<ILogEventSink>(() => new UnityOutputWindowSink(null));
|
||||
|
||||
Init(isFirst, projectPath, outputWindowSink);
|
||||
|
||||
if (isFirst)
|
||||
LogHeader(Application.unityVersion, projectPath);
|
||||
Serilog.Log.Debug("PATH: {Path}", projectPath);
|
||||
}
|
||||
|
||||
|
||||
static void LogHeader(string unityVersion, string solutionDir)
|
||||
{
|
||||
var os = System.Runtime.InteropServices.RuntimeInformation.OSDescription;
|
||||
var assisterVersion = Assister.Version;
|
||||
var syncModel = Synchronizer.Model.Utilities.Version;
|
||||
var hash = CommonTools.GetHashOfPath(solutionDir);
|
||||
Serilog.Log.Debug(
|
||||
"Beginning logging {OS}, Unity {U}, Unity Code Assist {A}, Communication Protocol {SM}, Project: '{Dir}', Project Hash: {Hash}",
|
||||
os, unityVersion, assisterVersion, syncModel, solutionDir, hash);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static string GetFilePath(string solutionDir)
|
||||
{
|
||||
var solutionHash = CommonTools.GetHashOfPath(solutionDir);
|
||||
var tempDir = System.IO.Path.GetTempPath();
|
||||
var fileName = $"UCA_U_LOG_{solutionHash}_.TXT"; // hour code will be appended to the end of file, so add a trailing '_'
|
||||
var filePath = System.IO.Path.Combine(tempDir, fileName);
|
||||
return filePath;
|
||||
}
|
||||
|
||||
static string GetVSFilePath(string solutionDir)
|
||||
{
|
||||
var solutionHash = CommonTools.GetHashOfPath(solutionDir);
|
||||
var tempDir = System.IO.Path.GetTempPath();
|
||||
var fileName = $"UCA_VS_LOG_{solutionHash}_.TXT"; // hour code will be appended to the end of file, so add a trailing '_'
|
||||
var filePath = System.IO.Path.Combine(tempDir, fileName);
|
||||
return filePath;
|
||||
}
|
||||
|
||||
|
||||
public static void Init(bool isFirst, string solutionDir, System.Lazy<ILogEventSink> outputWindowSink)
|
||||
{
|
||||
|
||||
FilePath = GetFilePath(solutionDir);
|
||||
VSFilePath = GetVSFilePath(solutionDir);
|
||||
|
||||
fileLevelSwitch = new LoggingLevelSwitch(fileMinLevel);
|
||||
outputWindowLevelSwitch = new LoggingLevelSwitch(outputWindowMinLevel);
|
||||
|
||||
var config = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.Enrich.With(new DomainHashEnricher());
|
||||
|
||||
const string outputTemplate = "{Timestamp:HH:mm:ss.fff} [U] [{Level:u3}] [{DomainHash}] {Message:lj}{NewLine}{Exception}";
|
||||
|
||||
config = config.WriteTo.PersistentFile(FilePath
|
||||
, outputTemplate: outputTemplate
|
||||
, shared: true
|
||||
, persistentFileRollingInterval: PersistentFileRollingInterval.Day
|
||||
, preserveLogFilename: true
|
||||
, levelSwitch: fileLevelSwitch
|
||||
, rollOnEachProcessRun: isFirst
|
||||
);
|
||||
|
||||
_outputWindowSink ??= outputWindowSink.Value;
|
||||
if (_outputWindowSink != null)
|
||||
config = config.WriteTo.Sink(_outputWindowSink, outputWindowMinLevel, outputWindowLevelSwitch);
|
||||
|
||||
_memorySink ??= new MemorySink(outputTemplate);
|
||||
config = config.WriteTo.Sink(_memorySink, fileMinLevel, null);
|
||||
|
||||
config = config.Destructure.With(new MyDestructuringPolicy());
|
||||
|
||||
Serilog.Log.Logger = config.CreateLogger();
|
||||
//switchableLogger.Set(config.CreateLogger(), disposePrev: true);
|
||||
|
||||
OnOptionsChanged();
|
||||
|
||||
//IsInitialized = true;
|
||||
}
|
||||
|
||||
public static void OnOptionsChanged()
|
||||
{
|
||||
// Since we don't use LogEventLevel.Fatal, we can use it for disabling sinks
|
||||
|
||||
var isLoggingToFile = OptionsIsLoggingToFile;
|
||||
var targetFileLevel = isLoggingToFile ? fileMinLevel : Serilog.Events.LogEventLevel.Fatal;
|
||||
if (fileLevelSwitch != null)
|
||||
fileLevelSwitch.MinimumLevel = targetFileLevel;
|
||||
|
||||
var isLoggingToOutputWindow = OptionsIsLoggingToOutputWindow;
|
||||
var targetOutputWindowLevel = isLoggingToOutputWindow ? outputWindowMinLevel : Serilog.Events.LogEventLevel.Fatal;
|
||||
if (outputWindowLevelSwitch != null)
|
||||
outputWindowLevelSwitch.MinimumLevel = targetOutputWindowLevel;
|
||||
}
|
||||
|
||||
//**-- UI for these two
|
||||
static bool OptionsIsLoggingToFile => true;
|
||||
static bool OptionsIsLoggingToOutputWindow => true;
|
||||
}
|
||||
|
||||
public class MyDestructuringPolicy : IDestructuringPolicy
|
||||
{
|
||||
// serilog cannot destruct StringArrayContainer by default, so do it manually
|
||||
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out Serilog.Events.LogEventPropertyValue? result)
|
||||
{
|
||||
if (value is Synchronizer.Model.StringArrayContainer sac)
|
||||
{
|
||||
var items = sac.Container.Select(item => propertyValueFactory.CreatePropertyValue(item, true));
|
||||
result = new Serilog.Events.SequenceValue(items);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Logger/ELogger.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Logger/ELogger.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 054dc6105589bce4081e205ac04bf169
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
131
Assets/Plugins/CodeAssist/Editor/Logger/MemorySink.cs
Normal file
131
Assets/Plugins/CodeAssist/Editor/Logger/MemorySink.cs
Normal file
|
@ -0,0 +1,131 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
using Serilog.Formatting;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Logger
|
||||
{
|
||||
//**--
|
||||
// remove this in unity???
|
||||
// need to serialize/deserialize data to survive domain reload, which will effect performance
|
||||
// right now data is lost during domain reloads, which makes its function kinda useless
|
||||
// or maybe move it to a external process like com.unity.process-server
|
||||
public class MemorySink : ILogEventSink
|
||||
{
|
||||
readonly ConcurrentQueue<LogEvent> logs;
|
||||
readonly ConcurrentQueue<LogEvent[]> warningLogs;
|
||||
readonly ConcurrentQueue<LogEvent[]> errorLogs;
|
||||
|
||||
const int logsLimit = 30;
|
||||
const int warningLimit = 5;
|
||||
const int errorLimit = 3;
|
||||
|
||||
readonly string outputTemplate;
|
||||
|
||||
public MemorySink(string outputTemplate)
|
||||
{
|
||||
this.outputTemplate = outputTemplate;
|
||||
|
||||
logs = new ConcurrentQueue<LogEvent>();
|
||||
warningLogs = new ConcurrentQueue<LogEvent[]>();
|
||||
errorLogs = new ConcurrentQueue<LogEvent[]>();
|
||||
}
|
||||
|
||||
public void Emit(LogEvent logEvent)
|
||||
{
|
||||
if (logEvent == null)
|
||||
return;
|
||||
|
||||
logs.Enqueue(logEvent);
|
||||
if (logs.Count > logsLimit)
|
||||
logs.TryDequeue(out _);
|
||||
|
||||
if (logEvent.Level == LogEventLevel.Warning)
|
||||
{
|
||||
var warningAndLeadingLogs = logs.ToArray();
|
||||
warningLogs.Enqueue(warningAndLeadingLogs);
|
||||
if (warningLogs.Count > warningLimit)
|
||||
warningLogs.TryDequeue(out _);
|
||||
}
|
||||
|
||||
if (logEvent.Level == LogEventLevel.Error)
|
||||
{
|
||||
var errorAndLeadingLogs = logs.ToArray();
|
||||
errorLogs.Enqueue(errorAndLeadingLogs);
|
||||
if (errorLogs.Count > errorLimit)
|
||||
errorLogs.TryDequeue(out _);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasError => !errorLogs.IsEmpty;
|
||||
public bool HasWarning => !warningLogs.IsEmpty;
|
||||
public int ErrorCount => errorLogs.Count;
|
||||
public int WarningCount => warningLogs.Count;
|
||||
|
||||
public string Export()
|
||||
{
|
||||
IFormatProvider? formatProvider = null;
|
||||
var formatter = new Serilog.Formatting.Display.MessageTemplateTextFormatter(
|
||||
outputTemplate, formatProvider);
|
||||
|
||||
var result = string.Empty;
|
||||
|
||||
using (var outputStream = new MemoryStream())
|
||||
{
|
||||
var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
|
||||
using var output = new StreamWriter(outputStream, encoding);
|
||||
if (!errorLogs.IsEmpty)
|
||||
{
|
||||
var errorArray = errorLogs.ToArray();
|
||||
foreach (var error in errorArray)
|
||||
{
|
||||
foreach (var logEvent in error)
|
||||
{
|
||||
formatter.Format(logEvent, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!warningLogs.IsEmpty)
|
||||
{
|
||||
var warningArray = warningLogs.ToArray();
|
||||
foreach (var warning in warningArray)
|
||||
{
|
||||
foreach (var logEvent in warning)
|
||||
{
|
||||
formatter.Format(logEvent, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!logs.IsEmpty)
|
||||
{
|
||||
var logArray = logs.ToArray();
|
||||
foreach (var logEvent in logArray)
|
||||
{
|
||||
formatter.Format(logEvent, output);
|
||||
}
|
||||
}
|
||||
|
||||
output.Flush();
|
||||
|
||||
outputStream.Seek(0, SeekOrigin.Begin);
|
||||
using var streamReader = new StreamReader(outputStream, encoding);
|
||||
result = streamReader.ReadToEnd();
|
||||
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Logger/MemorySink.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Logger/MemorySink.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0fe13269bf1182142a9b46409339fb5b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
47
Assets/Plugins/CodeAssist/Editor/Logger/UnitySink.cs
Normal file
47
Assets/Plugins/CodeAssist/Editor/Logger/UnitySink.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Serilog;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
using Serilog.Configuration;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Logger
|
||||
{
|
||||
public class UnityOutputWindowSink : ILogEventSink
|
||||
{
|
||||
private readonly IFormatProvider? _formatProvider;
|
||||
|
||||
public UnityOutputWindowSink(IFormatProvider? formatProvider)
|
||||
{
|
||||
_formatProvider = formatProvider;
|
||||
}
|
||||
|
||||
public void Emit(LogEvent logEvent)
|
||||
{
|
||||
var message = logEvent.RenderMessage(_formatProvider);
|
||||
|
||||
switch (logEvent.Level)
|
||||
{
|
||||
case LogEventLevel.Verbose:
|
||||
case LogEventLevel.Debug:
|
||||
case LogEventLevel.Information:
|
||||
UnityEngine.Debug.Log(message);
|
||||
break;
|
||||
case LogEventLevel.Warning:
|
||||
UnityEngine.Debug.LogWarning(message);
|
||||
break;
|
||||
case LogEventLevel.Error:
|
||||
case LogEventLevel.Fatal:
|
||||
UnityEngine.Debug.LogError(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Logger/UnitySink.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Logger/UnitySink.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3995562507d0dd147b1533d40e3de339
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
35
Assets/Plugins/CodeAssist/Editor/MainThreadDispatcher.cs
Normal file
35
Assets/Plugins/CodeAssist/Editor/MainThreadDispatcher.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class MainThreadDispatcher
|
||||
{
|
||||
readonly static ConcurrentBag<System.Action> actions;
|
||||
|
||||
static MainThreadDispatcher()
|
||||
{
|
||||
actions = new ConcurrentBag<System.Action>();
|
||||
EditorApplication.update += Update;
|
||||
}
|
||||
|
||||
static void Update()
|
||||
{
|
||||
while (actions.TryTake(out var action))
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(System.Action action) => actions.Add(action);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a8e4c653b47e4164b916eb282781b9ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
237
Assets/Plugins/CodeAssist/Editor/Monitor.cs
Normal file
237
Assets/Plugins/CodeAssist/Editor/Monitor.cs
Normal file
|
@ -0,0 +1,237 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class Monitor
|
||||
{
|
||||
private readonly static string tagManagerFilePath;
|
||||
private static System.DateTime previousTagManagerLastWrite;
|
||||
|
||||
private static bool isAppFocused;
|
||||
private static bool isAppFocusedOnTagManager;
|
||||
|
||||
private static int dirtyCounter;
|
||||
private static readonly Dictionary<GameObject, int> dirtyDict;
|
||||
|
||||
static Monitor()
|
||||
{
|
||||
tagManagerFilePath = CommonTools.GetTagManagerFilePath();
|
||||
previousTagManagerLastWrite = System.IO.File.GetLastWriteTime(tagManagerFilePath);
|
||||
|
||||
dirtyDict = new Dictionary<GameObject, int>();
|
||||
dirtyCounter = 0;
|
||||
|
||||
EditorApplication.hierarchyChanged += OnHierarchyChanged;
|
||||
EditorApplication.update += OnUpdate;
|
||||
Undo.postprocessModifications += MyPostprocessModificationsCallback;
|
||||
Undo.undoRedoPerformed += MyUndoCallback;
|
||||
Selection.selectionChanged += OnSelectionChanged;
|
||||
//EditorSceneManager.sceneOpened += EditorSceneManager_sceneOpened;
|
||||
EditorSceneManager.activeSceneChangedInEditMode += EditorSceneManager_activeSceneChangedInEditMode;
|
||||
|
||||
Application.logMessageReceived += Application_logMessageReceived;
|
||||
//System.Threading.Tasks.TaskScheduler.UnobservedTaskException +=
|
||||
}
|
||||
|
||||
private static void EditorSceneManager_activeSceneChangedInEditMode(Scene arg0, Scene arg1)
|
||||
{
|
||||
//Debug.Log("EditorSceneManager_activeSceneChangedInEditMode");
|
||||
OnHierarchyChanged();
|
||||
}
|
||||
|
||||
private static void EditorSceneManager_sceneOpened(Scene scene, OpenSceneMode mode)
|
||||
{
|
||||
Serilog.Log.Debug("Monitor {Event} scene:{Scene} mode:{Mode}", nameof(EditorSceneManager_sceneOpened), scene.name, mode);
|
||||
//Debug.Log("EditorSceneManager_sceneOpened");
|
||||
OnHierarchyChanged();
|
||||
}
|
||||
|
||||
static void OnUpdate()
|
||||
{
|
||||
string? currentEditorFocus = null;
|
||||
if (Selection.activeObject)
|
||||
currentEditorFocus = Selection.activeObject.GetType().ToString();
|
||||
|
||||
var currentTagManagerLastWrite = System.IO.File.GetLastWriteTime(tagManagerFilePath);
|
||||
if (currentTagManagerLastWrite != previousTagManagerLastWrite)
|
||||
{
|
||||
previousTagManagerLastWrite = currentTagManagerLastWrite;
|
||||
OnTagsOrLayersModified();
|
||||
}
|
||||
else if (currentEditorFocus == "UnityEditor.TagManager")
|
||||
{
|
||||
// since unity does not commit changes to the file immediately, checking if user is displaying and focusing on tag manager (tags & layers) inspector
|
||||
isAppFocusedOnTagManager = true;
|
||||
}
|
||||
|
||||
|
||||
if (isAppFocused != UnityEditorInternal.InternalEditorUtility.isApplicationActive)
|
||||
{
|
||||
isAppFocused = UnityEditorInternal.InternalEditorUtility.isApplicationActive;
|
||||
OnOnUnityEditorFocusChanged(isAppFocused);
|
||||
Serilog.Log.Debug("On focus {State}", isAppFocused);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnTagsOrLayersModified()
|
||||
{
|
||||
Serilog.Log.Debug("Monitor {Event}", nameof(OnTagsOrLayersModified));
|
||||
|
||||
Assister.SendTagsAndLayers();
|
||||
}
|
||||
|
||||
static void OnHierarchyChanged()
|
||||
{
|
||||
Serilog.Log.Debug("Monitor {Event}", nameof(OnHierarchyChanged));
|
||||
|
||||
// For requesting active doc's GO
|
||||
NetMQInitializer.Publisher?.SendHandshake();
|
||||
|
||||
if (ScriptFinder.GetActiveGameObject(out var activeGO))
|
||||
NetMQInitializer.Publisher?.SendGameObject(activeGO);
|
||||
//Assister.SendTagsAndLayers(); Don't send tags & layers here
|
||||
}
|
||||
|
||||
static UndoPropertyModification[] MyPostprocessModificationsCallback(UndoPropertyModification[] modifications)
|
||||
{
|
||||
Serilog.Log.Debug("Monitor {Event}", nameof(MyPostprocessModificationsCallback));
|
||||
|
||||
foreach (var modification in modifications)
|
||||
{
|
||||
var target = modification.currentValue?.target;
|
||||
SetDirty(target);
|
||||
}
|
||||
|
||||
// here, you can perform processing of the recorded modifications before returning them
|
||||
return modifications;
|
||||
}
|
||||
|
||||
static void MyUndoCallback()
|
||||
{
|
||||
Serilog.Log.Debug("Monitor {Event}", nameof(MyUndoCallback));
|
||||
// code for the action to take on Undo
|
||||
}
|
||||
|
||||
static void OnOnUnityEditorFocusChanged(bool isFocused)
|
||||
{
|
||||
if (!isFocused)
|
||||
{
|
||||
if (isAppFocusedOnTagManager)
|
||||
{
|
||||
isAppFocusedOnTagManager = false;
|
||||
OnTagsOrLayersModified();
|
||||
}
|
||||
|
||||
OnSelectionChanged();
|
||||
FlushAllDirty();
|
||||
/*
|
||||
Serilog.Log.Debug("exporting {Count} objects", selectedObjects.Count);
|
||||
|
||||
//**--if too many
|
||||
foreach (var obj in selectedObjects)
|
||||
{
|
||||
if (obj is GameObject go)
|
||||
NetMQInitializer.Publisher.SendGameObject(go);
|
||||
}
|
||||
|
||||
selectedObjects.Clear();
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static void OnSelectionChanged()
|
||||
{
|
||||
|
||||
//**--check order, last selected should be sent last as well
|
||||
//**--limit here, what if too many?
|
||||
//selectedObjects.UnionWith(Selection.objects);
|
||||
foreach(var so in Selection.objects)
|
||||
{
|
||||
SetDirty(so);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetDirty(Object? obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return;
|
||||
else if (obj is GameObject go && go)
|
||||
SetDirty(go);
|
||||
else if (obj is Component component && component)
|
||||
SetDirty(component.gameObject);
|
||||
//else
|
||||
//;//**--scriptable obj
|
||||
}
|
||||
|
||||
public static void SetDirty(GameObject go)
|
||||
{
|
||||
dirtyCounter++;
|
||||
dirtyDict[go] = dirtyCounter;
|
||||
}
|
||||
|
||||
static void FlushAllDirty()
|
||||
{
|
||||
// Sending order is important, must send them in the same order as they are added to/modified in the collection
|
||||
// Using dict instead of hashset because of that. Dict value is used as add/modify order
|
||||
|
||||
var sortedDict = from entry in dirtyDict orderby entry.Value descending select entry;
|
||||
|
||||
foreach (var entry in sortedDict)
|
||||
{
|
||||
var go = entry.Key;
|
||||
NetMQInitializer.Publisher?.SendGameObject(go);
|
||||
}
|
||||
|
||||
dirtyDict.Clear();
|
||||
dirtyCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
private static void Application_logMessageReceived(string condition, string stackTrace, LogType type)
|
||||
{
|
||||
if (type != LogType.Exception && type != LogType.Error && type != LogType.Warning)
|
||||
return;
|
||||
|
||||
if (!stackTrace.Contains("Meryel.UnityCodeAssist.Editor"))
|
||||
return;
|
||||
|
||||
var typeStr = type.ToString();
|
||||
|
||||
NetMQInitializer.Publisher?.SendErrorReport(condition, stackTrace, typeStr);
|
||||
}
|
||||
|
||||
|
||||
public static void LazyLoad(string category)
|
||||
{
|
||||
if (category == "PlayerPrefs")
|
||||
{
|
||||
Preferences.PreferenceMonitor.InstanceOfPlayerPrefs.Bump();
|
||||
}
|
||||
else if(category == "EditorPrefs")
|
||||
{
|
||||
Preferences.PreferenceMonitor.InstanceOfEditorPrefs.Bump();
|
||||
}
|
||||
else if(category == "InputManager")
|
||||
{
|
||||
Input.InputManagerMonitor.Instance.Bump();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serilog.Log.Error("Invalid LazyLoad category {Category}", category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/Monitor.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/Monitor.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5a5c5865a2051964ebed462471427777
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
95
Assets/Plugins/CodeAssist/Editor/NetMQInitializer.cs
Normal file
95
Assets/Plugins/CodeAssist/Editor/NetMQInitializer.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class NetMQInitializer
|
||||
{
|
||||
public static NetMQPublisher? Publisher;
|
||||
|
||||
static NetMQInitializer()
|
||||
{
|
||||
EditorApplication.quitting += EditorApplication_quitting;
|
||||
AssemblyReloadEvents.beforeAssemblyReload += AssemblyReloadEvents_beforeAssemblyReload;
|
||||
AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadEvents_afterAssemblyReload;
|
||||
|
||||
RunOnceOnUpdate(Initialize);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Serilog.Log.Debug("NetMQ initializing");
|
||||
|
||||
AsyncIO.ForceDotNet.Force();
|
||||
|
||||
Serilog.Log.Debug("NetMQ cleaning up (true)");
|
||||
NetMQ.NetMQConfig.Cleanup(true);
|
||||
|
||||
Serilog.Log.Debug("NetMQ constructing");
|
||||
Publisher = new NetMQPublisher();
|
||||
|
||||
RunOnShutdown(OnShutDown);
|
||||
Serilog.Log.Debug("NetMQ initialized");
|
||||
}
|
||||
|
||||
private static void OnShutDown()
|
||||
{
|
||||
Serilog.Log.Debug("NetMQ OnShutDown");
|
||||
Clear();
|
||||
}
|
||||
|
||||
private static void AssemblyReloadEvents_afterAssemblyReload()
|
||||
{
|
||||
Serilog.Log.Debug("NetMQ AssemblyReloadEvents_afterAssemblyReload");
|
||||
}
|
||||
|
||||
//private static void AssemblyReloadEvents_beforeAssemblyReload() => Clear();
|
||||
private static void AssemblyReloadEvents_beforeAssemblyReload()
|
||||
{
|
||||
Serilog.Log.Debug("NetMQ AssemblyReloadEvents_beforeAssemblyReload");
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
private static void EditorApplication_quitting()
|
||||
{
|
||||
Serilog.Log.Debug("NetMQ EditorApplication_quitting");
|
||||
|
||||
Publisher?.SendDisconnect();
|
||||
Clear();
|
||||
}
|
||||
|
||||
static void Clear() => Publisher?.Clear();
|
||||
|
||||
|
||||
private static void RunOnceOnUpdate(Action action)
|
||||
{
|
||||
void callback()
|
||||
{
|
||||
EditorApplication.update -= callback;
|
||||
action();
|
||||
}
|
||||
|
||||
EditorApplication.update += callback;
|
||||
}
|
||||
|
||||
private static void RunOnShutdown(Action action)
|
||||
{
|
||||
// Mono on OSX has all kinds of quirks on AppDomain shutdown
|
||||
//if (!VisualStudioEditor.IsWindows)
|
||||
//return;
|
||||
#if !UNITY_EDITOR_WIN
|
||||
return;
|
||||
#else
|
||||
AppDomain.CurrentDomain.DomainUnload += (_, __) => action();
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/NetMQInitializer.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/NetMQInitializer.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ab712cada0ef881478108b33d3062ac3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
792
Assets/Plugins/CodeAssist/Editor/NetMQPublisher.cs
Normal file
792
Assets/Plugins/CodeAssist/Editor/NetMQPublisher.cs
Normal file
|
@ -0,0 +1,792 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
using System.Threading;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
//using CancellationToken = System.Threading;
|
||||
using Application = UnityEngine.Application;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
//**--
|
||||
// can also do this for better clear, sometimes it gets locked
|
||||
// https://answers.unity.com/questions/704066/callback-before-unity-reloads-editor-assemblies.html#
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
public class NetMQPublisher : Synchronizer.Model.IProcessor
|
||||
{
|
||||
PublisherSocket? pubSocket;
|
||||
readonly string pubConnString;
|
||||
|
||||
Task? pullTask;
|
||||
CancellationTokenSource? pullTaskCancellationTokenSource;
|
||||
|
||||
readonly Synchronizer.Model.Manager syncMngr;
|
||||
|
||||
public List<Synchronizer.Model.Connect> clients;
|
||||
|
||||
Synchronizer.Model.Connect? _self;
|
||||
|
||||
Synchronizer.Model.Connect Self => _self!;
|
||||
|
||||
void InitializeSelf()
|
||||
{
|
||||
var projectPath = CommonTools.GetProjectPath();
|
||||
_self = new Synchronizer.Model.Connect()
|
||||
{
|
||||
ModelVersion = Synchronizer.Model.Utilities.Version,
|
||||
ProjectPath = projectPath,
|
||||
ProjectName = getProjectName(),
|
||||
ContactInfo = $"Unity {Application.unityVersion}",
|
||||
AssemblyVersion = Assister.Version,
|
||||
};
|
||||
|
||||
string getProjectName()
|
||||
{
|
||||
string[] s = projectPath.Split('/');
|
||||
string projectName = s[s.Length - 2];
|
||||
//Logg("project = " + projectName);
|
||||
return projectName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void LogContext()
|
||||
{
|
||||
Serilog.Log.Debug("LogginContext begin");
|
||||
|
||||
//var context = typeof(NetMQConfig).GetProperty("Context", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
|
||||
var context = typeof(NetMQConfig).GetField("s_ctx", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
|
||||
Serilog.Log.Debug("context: {Context}", context);
|
||||
|
||||
if (context == null)
|
||||
return;
|
||||
|
||||
var starting = context.GetType().GetField("m_starting", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(context);
|
||||
Serilog.Log.Debug("starting: {Starting}", starting);
|
||||
|
||||
var terminating = context.GetType().GetField("m_terminating", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(context);
|
||||
Serilog.Log.Debug("terminating: {Terminating}", terminating);
|
||||
|
||||
var sockets = context.GetType().GetField("m_sockets", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(context);
|
||||
//Logg("sockets:" + sockets);
|
||||
//var socketList = sockets as System.Collections.IList;
|
||||
if (sockets is System.Collections.IList socketList)
|
||||
{
|
||||
Serilog.Log.Debug("socketList: {SocketList} [{Count}]", socketList, socketList.Count);
|
||||
|
||||
foreach (var socketItem in socketList)
|
||||
{
|
||||
Serilog.Log.Debug("socketItem: {SocketItem}", socketItem);
|
||||
}
|
||||
}
|
||||
|
||||
var endPoints = context.GetType().GetField("m_endpoints", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(context);
|
||||
//Logg("endPoints:" + endPoints);
|
||||
//var endPointDict = endPoints as System.Collections.IDictionary;
|
||||
if (endPoints is System.Collections.IDictionary endPointDict)
|
||||
{
|
||||
Serilog.Log.Debug("endPointDict: {EndPointDict} ,{Count}", endPointDict, endPointDict.Count);
|
||||
|
||||
foreach (var endPointDictKey in endPointDict.Keys)
|
||||
{
|
||||
Serilog.Log.Debug("endPointDictKey: {EndPointDictKey} => {EndPointDictValue}", endPointDictKey, endPointDict[endPointDictKey]);
|
||||
}
|
||||
}
|
||||
|
||||
Serilog.Log.Debug("LogginContext end");
|
||||
}
|
||||
|
||||
bool isBind = false;
|
||||
public NetMQPublisher()
|
||||
{
|
||||
// LogContext();
|
||||
|
||||
Serilog.Log.Debug("NetMQ server initializing, begin");
|
||||
|
||||
InitializeSelf();
|
||||
|
||||
clients = new List<Synchronizer.Model.Connect>();
|
||||
syncMngr = new Synchronizer.Model.Manager(this);
|
||||
|
||||
var (pubSub, pushPull) = Synchronizer.Model.Utilities.GetConnectionString(Self!.ProjectPath);
|
||||
pubConnString = pubSub;
|
||||
|
||||
//NetMQConfig.Linger = new TimeSpan(0);
|
||||
|
||||
//pub = new Publisher();
|
||||
pubSocket = new PublisherSocket();
|
||||
|
||||
pubSocket.Options.SendHighWatermark = 1000;
|
||||
Serilog.Log.Debug("NetMQ server initializing, Publisher socket binding... {PubConnString}", pubConnString);
|
||||
//pubSocket.Bind("tcp://127.0.0.1:12349");
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
pubSocket.Bind(pubConnString);
|
||||
isBind = true;
|
||||
Serilog.Log.Debug("NetMQ server initializing, Publisher socket bound");
|
||||
}
|
||||
catch (AddressAlreadyInUseException ex)
|
||||
{
|
||||
Serilog.Log.Warning(ex, "NetMQ.AddressAlreadyInUseException");
|
||||
LogContext();
|
||||
Serilog.Log.Warning("NetMQ.AddressAlreadyInUseException disposing pubSocket");
|
||||
pubSocket.Dispose();
|
||||
pubSocket = null;
|
||||
return;
|
||||
}
|
||||
catch (System.Net.Sockets.SocketException ex)
|
||||
{
|
||||
Serilog.Log.Warning(ex, "Socket exception");
|
||||
LogContext();
|
||||
Serilog.Log.Warning("Socket exception disposing pubSocket");
|
||||
pubSocket.Dispose();
|
||||
pubSocket = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//pubSocket.SendReady += PubSocket_SendReady;
|
||||
//SendConnect();
|
||||
|
||||
pullTaskCancellationTokenSource = new CancellationTokenSource();
|
||||
//pullThread = new System.Threading.Thread(async () => await PullAsync(conn.pushPull, pullThreadCancellationTokenSource.Token));
|
||||
//pullThread = new System.Threading.Thread(() => InitPull(conn.pushPull, pullTaskCancellationTokenSource.Token));
|
||||
//pullThread.Start();
|
||||
//Task.Run(() => InitPullAsync());
|
||||
|
||||
/*
|
||||
pullTask = Task.Factory.StartNew(
|
||||
() => InitPull(conn.pushPull, pullTaskCancellationTokenSource.Token), pullTaskCancellationTokenSource.Token,
|
||||
System.Threading.Tasks.TaskCreationOptions.LongRunning, System.Threading.Tasks.TaskScheduler.Current);
|
||||
*/
|
||||
|
||||
|
||||
pullTask = Task.Factory.StartNew(
|
||||
() => InitPull(pushPull, pullTaskCancellationTokenSource.Token),
|
||||
System.Threading.Tasks.TaskCreationOptions.LongRunning);
|
||||
|
||||
//InitPull(conn.pushPull);
|
||||
|
||||
Serilog.Log.Debug("NetMQ server initializing, initialized");
|
||||
|
||||
// need to sleep here, clients will take some time to start subscribing
|
||||
// https://github.com/zeromq/netmq/issues/482#issuecomment-182200323
|
||||
Thread.Sleep(1000);
|
||||
SendConnect();
|
||||
}
|
||||
|
||||
|
||||
private void InitPull(string connectionString, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var runtime = new NetMQRuntime())
|
||||
{
|
||||
runtime.Run(//cancellationToken,
|
||||
PullAsync(connectionString, cancellationToken)
|
||||
);
|
||||
Serilog.Log.Debug("Puller runtime ended");
|
||||
}
|
||||
Serilog.Log.Debug("Puller runtime disposed");
|
||||
}
|
||||
|
||||
async Task PullAsync(string connectionString, CancellationToken cancellationToken)
|
||||
{
|
||||
Serilog.Log.Debug("Puller begin");
|
||||
using (var pullSocket = new PullSocket(connectionString))
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
string header, content;
|
||||
try
|
||||
{
|
||||
var headerTuple = await pullSocket.ReceiveFrameStringAsync(cancellationToken);
|
||||
var contentTuple = await pullSocket.ReceiveFrameStringAsync(cancellationToken);
|
||||
header = headerTuple.Item1;
|
||||
content = contentTuple.Item1;
|
||||
}
|
||||
catch (System.Threading.Tasks.TaskCanceledException)
|
||||
{
|
||||
// Cancellation (token) requested
|
||||
break;
|
||||
}
|
||||
Serilog.Log.Debug("Pulled: {Header}, {Content}", header, content);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
break;
|
||||
|
||||
//**--optimize here, pass only params
|
||||
MainThreadDispatcher.Add(() => syncMngr.ProcessMessage(header, content));
|
||||
//syncMngr.ProcessMessage(header.Item1, content.Item1);
|
||||
}
|
||||
|
||||
Serilog.Log.Debug("Puller closing");
|
||||
|
||||
pullSocket.Unbind(connectionString);
|
||||
pullSocket.Close();
|
||||
|
||||
Serilog.Log.Debug("Puller closed");
|
||||
}
|
||||
|
||||
Serilog.Log.Debug("Puller disposed");
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
// LogContext();
|
||||
|
||||
Serilog.Log.Debug("NetMQ clearing, begin 1, pullTaskCancellationTokenSource: {PullTaskCancellationTokenSource}", pullTaskCancellationTokenSource);
|
||||
pullTaskCancellationTokenSource?.Cancel();
|
||||
|
||||
Serilog.Log.Verbose("NetMQ clearing, begin 2, pubSocket: {PubSocket}", pubSocket);
|
||||
var pubSocketDebugStr = pubSocket?.ToString();
|
||||
Serilog.Log.Debug("NetMQ clearing, begin 3, isBind: {IsBind}", isBind);
|
||||
if (isBind)
|
||||
{
|
||||
pubSocket?.Unbind(pubConnString);
|
||||
isBind = false;
|
||||
}
|
||||
Serilog.Log.Verbose("NetMQ clearing, begin 4");
|
||||
pubSocket?.Close();
|
||||
Serilog.Log.Verbose("NetMQ clearing, begin 5");
|
||||
pubSocket?.Dispose();
|
||||
Serilog.Log.Verbose("NetMQ clearing, begin 6");
|
||||
pubSocket = null;
|
||||
Serilog.Log.Debug("NetMQ clearing, publisher closed pubSocketDebugStr: {PubSocketDebugStr}", pubSocketDebugStr);
|
||||
|
||||
try
|
||||
{
|
||||
Serilog.Log.Debug("NetMQ clearing, Task 1 begin");
|
||||
|
||||
if (pullTask != null && !pullTask.Wait(1000))
|
||||
Serilog.Log.Warning("NetMQ clearing, pull task termination failed");
|
||||
|
||||
Serilog.Log.Verbose("NetMQ clearing, Task 2 waited");
|
||||
|
||||
pullTask?.Dispose();
|
||||
pullTask = null;
|
||||
|
||||
Serilog.Log.Debug("NetMQ clearing, Task 3 disposed");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Console.WriteLine($"\n{nameof(OperationCanceledException)} thrown\n");
|
||||
Serilog.Log.Error(ex, "NetMQ clearing, pull task");
|
||||
}
|
||||
finally
|
||||
{
|
||||
pullTaskCancellationTokenSource?.Dispose();
|
||||
pullTaskCancellationTokenSource = null;
|
||||
Serilog.Log.Debug("NetMQ clearing, task cancelled");
|
||||
}
|
||||
|
||||
Serilog.Log.Debug("NetMQ clearing, cleaning up");
|
||||
//pullSocket?.Close();
|
||||
NetMQConfig.Cleanup(false); // Must be here to work more than once. Also argument false is important, otherwise might freeze Unity upon exit or domain reload
|
||||
//pullThread?.Abort();
|
||||
Serilog.Log.Debug("NetMQ clearing, cleared");
|
||||
}
|
||||
|
||||
string SerializeObject<T>(T obj)
|
||||
where T : class
|
||||
{
|
||||
// Odin cant serialize string arrays, https://github.com/TeamSirenix/odin-serializer/issues/26
|
||||
//var buffer = OdinSerializer.SerializationUtility.SerializeValue<T>(obj, OdinSerializer.DataFormat.JSON);
|
||||
//var str = System.Text.Encoding.UTF8.GetString(buffer, 0, buffer.Length);
|
||||
|
||||
// Newtonsoft works fine, but needs package reference
|
||||
//var str = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
|
||||
|
||||
// not working
|
||||
//var str = EditorJsonUtility.ToJson(obj);
|
||||
|
||||
// needs nuget
|
||||
//System.Text.Json.JsonSerializer;
|
||||
|
||||
var str = TinyJson.JsonWriter.ToJson(obj);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void SendAux(Synchronizer.Model.IMessage message, bool logContent = true)
|
||||
{
|
||||
if (message == null)
|
||||
return;
|
||||
|
||||
SendAux(message.GetType().Name, message, logContent);
|
||||
}
|
||||
|
||||
void SendAux(string messageType, object content, bool logContent = true)
|
||||
{
|
||||
if (logContent)
|
||||
Serilog.Log.Debug("Publishing {MessageType} {@Content}", messageType, content);
|
||||
else
|
||||
Serilog.Log.Debug("Publishing {MessageType}", messageType);
|
||||
|
||||
var publisher = pubSocket;
|
||||
if (publisher != null)
|
||||
publisher.SendMoreFrame(messageType).SendFrame(SerializeObject(content));
|
||||
else
|
||||
Serilog.Log.Error("Publisher socket is null");
|
||||
}
|
||||
|
||||
public void SendConnect()
|
||||
{
|
||||
var connect = Self;
|
||||
|
||||
SendAux(connect);
|
||||
}
|
||||
|
||||
public void SendDisconnect()
|
||||
{
|
||||
var disconnect = new Synchronizer.Model.Disconnect()
|
||||
{
|
||||
ModelVersion = Self.ModelVersion,
|
||||
ProjectPath = Self.ProjectPath,
|
||||
ProjectName = Self.ProjectName,
|
||||
ContactInfo = Self.ContactInfo,
|
||||
AssemblyVersion = Self.AssemblyVersion,
|
||||
};
|
||||
|
||||
SendAux(disconnect);
|
||||
}
|
||||
|
||||
public void SendConnectionInfo()
|
||||
{
|
||||
var connectionInfo = new Synchronizer.Model.ConnectionInfo()
|
||||
{
|
||||
ModelVersion = Self.ModelVersion,
|
||||
ProjectPath = Self.ProjectPath,
|
||||
ProjectName = Self.ProjectName,
|
||||
ContactInfo = Self.ContactInfo,
|
||||
AssemblyVersion = Self.AssemblyVersion,
|
||||
};
|
||||
|
||||
SendAux(connectionInfo);
|
||||
}
|
||||
|
||||
public void SendHandshake()
|
||||
{
|
||||
var handshake = new Synchronizer.Model.Handshake();
|
||||
|
||||
SendAux(handshake);
|
||||
}
|
||||
|
||||
public void SendRequestInternalLog()
|
||||
{
|
||||
var requestInternalLog = new Synchronizer.Model.RequestInternalLog();
|
||||
|
||||
SendAux(requestInternalLog);
|
||||
}
|
||||
|
||||
public void SendInternalLog()
|
||||
{
|
||||
var internalLog = new Synchronizer.Model.InternalLog()
|
||||
{
|
||||
LogContent = Logger.ELogger.GetInternalLogContent(),
|
||||
};
|
||||
|
||||
SendAux(internalLog, logContent: false);
|
||||
}
|
||||
|
||||
|
||||
void SendStringArrayAux(string id, string[] array)
|
||||
{
|
||||
var stringArray = new Synchronizer.Model.StringArray()
|
||||
{
|
||||
Id = id,
|
||||
Array = array,
|
||||
};
|
||||
|
||||
SendAux(stringArray);
|
||||
}
|
||||
|
||||
void SendStringArrayContainerAux(params (string id, string[] array)[] container)
|
||||
{
|
||||
var stringArrayContainer = new Synchronizer.Model.StringArrayContainer()
|
||||
{
|
||||
Container = new Synchronizer.Model.StringArray[container.Length],
|
||||
};
|
||||
|
||||
for (int i = 0; i < container.Length; i++)
|
||||
{
|
||||
stringArrayContainer.Container[i] = new Synchronizer.Model.StringArray
|
||||
{
|
||||
Id = container[i].id,
|
||||
Array = container[i].array
|
||||
};
|
||||
}
|
||||
|
||||
SendAux(stringArrayContainer);
|
||||
}
|
||||
|
||||
public void SendTags(string[] tags) =>
|
||||
SendStringArrayAux(Synchronizer.Model.Ids.Tags, tags);
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
var tags = new Synchronizer.Model.Tags()
|
||||
{
|
||||
TagArray = tagArray,
|
||||
};
|
||||
|
||||
var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(tags);
|
||||
|
||||
pubSocket.SendMoreFrame(nameof(Synchronizer.Model.Tags)).SendFrame(serialized);
|
||||
|
||||
|
||||
}*/
|
||||
|
||||
public void SendLayers(string[] layerIndices, string[] layerNames)
|
||||
{
|
||||
/*
|
||||
var layers = new Synchronizer.Model.Layers()
|
||||
{
|
||||
LayerIndices = layerIndices,
|
||||
LayerNames = layerNames,
|
||||
};
|
||||
|
||||
var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(layers);
|
||||
|
||||
pubSocket.SendMoreFrame(nameof(Synchronizer.Model.Layers)).SendFrame(serialized);
|
||||
*/
|
||||
|
||||
//SendStringArrayAux(Synchronizer.Model.Ids.Layers, layerNames);
|
||||
//SendStringArrayAux(Synchronizer.Model.Ids.LayerIndices, layerIndices);
|
||||
SendStringArrayContainerAux(
|
||||
(Synchronizer.Model.Ids.Layers, layerNames),
|
||||
(Synchronizer.Model.Ids.LayerIndices, layerIndices)
|
||||
);
|
||||
}
|
||||
|
||||
public void SendSortingLayers(string[] sortingLayers, string[] sortingLayerIds, string[] sortingLayerValues)
|
||||
{
|
||||
//SendStringArrayAux(Synchronizer.Model.Ids.SortingLayers, sortingLayers);
|
||||
//SendStringArrayAux(Synchronizer.Model.Ids.SortingLayerIds, sortingLayerIds);
|
||||
//SendStringArrayAux(Synchronizer.Model.Ids.SortingLayerValues, sortingLayerValues);
|
||||
|
||||
SendStringArrayContainerAux(
|
||||
(Synchronizer.Model.Ids.SortingLayers, sortingLayers),
|
||||
(Synchronizer.Model.Ids.SortingLayerIds, sortingLayerIds),
|
||||
(Synchronizer.Model.Ids.SortingLayerValues, sortingLayerValues)
|
||||
);
|
||||
}
|
||||
|
||||
public void SendPlayerPrefs(string[] playerPrefKeys, string[] playerPrefValues,
|
||||
string[] playerPrefStringKeys, string[] playerPrefIntegerKeys, string[] playerPrefFloatKeys)
|
||||
{
|
||||
SendStringArrayContainerAux(
|
||||
(Synchronizer.Model.Ids.PlayerPrefKeys, playerPrefKeys),
|
||||
(Synchronizer.Model.Ids.PlayerPrefValues, playerPrefValues),
|
||||
(Synchronizer.Model.Ids.PlayerPrefStringKeys, playerPrefStringKeys),
|
||||
(Synchronizer.Model.Ids.PlayerPrefIntegerKeys, playerPrefIntegerKeys),
|
||||
(Synchronizer.Model.Ids.PlayerPrefFloatKeys, playerPrefFloatKeys)
|
||||
);
|
||||
}
|
||||
|
||||
public void SendEditorPrefs(string[] editorPrefKeys, string[] editorPrefValues,
|
||||
string[] editorPrefStringKeys, string[] editorPrefIntegerKeys, string[] editorPrefFloatKeys,
|
||||
string[] editorPrefBooleanKeys)
|
||||
{
|
||||
SendStringArrayContainerAux(
|
||||
(Synchronizer.Model.Ids.EditorPrefKeys, editorPrefKeys),
|
||||
(Synchronizer.Model.Ids.EditorPrefValues, editorPrefValues),
|
||||
(Synchronizer.Model.Ids.EditorPrefStringKeys, editorPrefStringKeys),
|
||||
(Synchronizer.Model.Ids.EditorPrefIntegerKeys, editorPrefIntegerKeys),
|
||||
(Synchronizer.Model.Ids.EditorPrefFloatKeys, editorPrefFloatKeys),
|
||||
(Synchronizer.Model.Ids.EditorPrefBooleanKeys, editorPrefBooleanKeys)
|
||||
);
|
||||
}
|
||||
|
||||
public void SendInputManager(string[] axisNames, string[] axisInfos, string[] buttonKeys, string[] buttonAxis, string[] joystickNames)
|
||||
{
|
||||
SendStringArrayContainerAux(
|
||||
(Synchronizer.Model.Ids.InputManagerAxes, axisNames),
|
||||
(Synchronizer.Model.Ids.InputManagerAxisInfos, axisInfos),
|
||||
(Synchronizer.Model.Ids.InputManagerButtonKeys, buttonKeys),
|
||||
(Synchronizer.Model.Ids.InputManagerButtonAxis, buttonAxis),
|
||||
(Synchronizer.Model.Ids.InputManagerJoystickNames, joystickNames)
|
||||
);
|
||||
}
|
||||
|
||||
public void SendScriptMissing(string component)
|
||||
{
|
||||
var scriptMissing = new Synchronizer.Model.ScriptMissing()
|
||||
{
|
||||
Component = component,
|
||||
};
|
||||
|
||||
SendAux(scriptMissing);
|
||||
}
|
||||
|
||||
public void SendGameObject(GameObject go)
|
||||
{
|
||||
if (!go)
|
||||
return;
|
||||
|
||||
Serilog.Log.Debug("SendGO: {GoName}", go.name);
|
||||
|
||||
var dataOfSelf = go.ToSyncModel(priority:10000);
|
||||
if (dataOfSelf != null)
|
||||
SendAux(dataOfSelf);
|
||||
|
||||
var dataOfHierarchy = go.ToSyncModelOfHierarchy();
|
||||
if (dataOfHierarchy != null)
|
||||
{
|
||||
foreach (var doh in dataOfHierarchy)
|
||||
SendAux(doh);
|
||||
}
|
||||
|
||||
var dataOfComponents = go.ToSyncModelOfComponents();
|
||||
if (dataOfComponents != null)
|
||||
{
|
||||
foreach (var doc in dataOfComponents)
|
||||
SendAux(doc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SendScriptableObject(ScriptableObject so)
|
||||
{
|
||||
Serilog.Log.Debug("SendSO: {SoName}", so.name);
|
||||
|
||||
var dataOfSo = so.ToSyncModel();
|
||||
if (dataOfSo != null)
|
||||
SendAux(dataOfSo);
|
||||
}
|
||||
|
||||
public void SendAnalyticsEvent(string type, string content)
|
||||
{
|
||||
var dataOfAe = new Synchronizer.Model.AnalyticsEvent()
|
||||
{
|
||||
EventType = type,
|
||||
EventContent = content
|
||||
};
|
||||
SendAux(dataOfAe);
|
||||
}
|
||||
|
||||
public void SendErrorReport(string errorMessage, string stack, string type)
|
||||
{
|
||||
var dataOfER = new Synchronizer.Model.ErrorReport()
|
||||
{
|
||||
ErrorMessage = errorMessage,
|
||||
ErrorStack = stack,
|
||||
ErrorType = type,
|
||||
};
|
||||
SendAux(dataOfER);
|
||||
}
|
||||
|
||||
public void SendRequestVerboseType(string type, string docPath)
|
||||
{
|
||||
var dataOfRVT = new Synchronizer.Model.RequestVerboseType()
|
||||
{
|
||||
Type = type,
|
||||
DocPath = docPath,
|
||||
};
|
||||
SendAux(dataOfRVT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
string Synchronizer.Model.IProcessor.Serialize<T>(T value)
|
||||
{
|
||||
//return System.Text.Json.JsonSerializer.Serialize<T>(value);
|
||||
//return Newtonsoft.Json.JsonConvert.SerializeObject(value);
|
||||
return SerializeObject(value);
|
||||
}
|
||||
T Synchronizer.Model.IProcessor.Deserialize<T>(string data)
|
||||
{
|
||||
//return System.Text.Json.JsonSerializer.Deserialize<T>(data)!;
|
||||
//return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(data)!;
|
||||
return TinyJson.JsonParser.FromJson<T>(data)!;
|
||||
|
||||
//byte[] buffer = System.Text.Encoding.UTF8.GetBytes(data);
|
||||
//T val = OdinSerializer.SerializationUtility.DeserializeValue<T>(buffer, OdinSerializer.DataFormat.JSON);
|
||||
//return val;
|
||||
}
|
||||
|
||||
//**--make sure all Synchronizer.Model.IProcessor.Process methods are thread-safe
|
||||
|
||||
// a new client has connected
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.Connect connect)
|
||||
{
|
||||
if (connect.ModelVersion != Self.ModelVersion)
|
||||
{
|
||||
Serilog.Log.Error("Version mismatch with {ContactInfo}. Please update your asset and reinstall the Visual Studio extension. {ContactModel} != {SelfModel}", connect.ContactInfo, connect.ModelVersion, Self.ModelVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connect.ProjectPath != Self.ProjectPath)
|
||||
{
|
||||
Serilog.Log.Error("Project mismatch with {ProjectName}. '{ConnectPath}' != '{SelfPath}'", connect.ProjectName, connect.ProjectPath, Self.ProjectPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clients.Any(c => c.ContactInfo == connect.ContactInfo))
|
||||
{
|
||||
clients.Add(connect);
|
||||
}
|
||||
|
||||
SendHandshake();
|
||||
if (ScriptFinder.GetActiveGameObject(out var activeGO))
|
||||
SendGameObject(activeGO);
|
||||
Assister.SendTagsAndLayers();
|
||||
}
|
||||
|
||||
// a new client is online and requesting connection
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestConnect requestConnect)
|
||||
{
|
||||
SendConnect();
|
||||
}
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.Disconnect disconnect)
|
||||
{
|
||||
var client = clients.FirstOrDefault(c => c.ContactInfo == disconnect.ContactInfo);
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
clients.Remove(client);
|
||||
}
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ConnectionInfo connectionInfo)
|
||||
{
|
||||
if (connectionInfo.ModelVersion != Self.ModelVersion)
|
||||
{
|
||||
Serilog.Log.Error("Version mismatch with {ContactInfo}. Please update your asset and reinstall the Visual Studio extension. {ContactModel} != {SelfModel}", connectionInfo.ContactInfo, connectionInfo.ModelVersion, Self.ModelVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionInfo.ProjectPath != Self.ProjectPath)
|
||||
{
|
||||
Serilog.Log.Error("Project mismatch with {ProjectName}. '{ConnectPath}' != '{SelfPath}'", connectionInfo.ProjectName, connectionInfo.ProjectPath, Self.ProjectPath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clients.Any(c => c.ContactInfo == connectionInfo.ContactInfo))
|
||||
{
|
||||
SendConnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
SendHandshake();
|
||||
if (ScriptFinder.GetActiveGameObject(out var activeGO))
|
||||
SendGameObject(activeGO);
|
||||
Assister.SendTagsAndLayers();
|
||||
}
|
||||
}
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestConnectionInfo requestConnectionInfo)
|
||||
{
|
||||
SendConnectionInfo();
|
||||
}
|
||||
/*
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.Layers layers)
|
||||
{
|
||||
|
||||
}
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.Tags tags)
|
||||
{
|
||||
|
||||
}
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.SortingLayers sortingLayers)
|
||||
{
|
||||
|
||||
}*/
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.StringArray stringArray)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.StringArray)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.StringArrayContainer stringArrayContainer)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.StringArrayContainer)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.GameObject gameObject)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.GameObject)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ComponentData component)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ComponentData)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestScript requestScript)
|
||||
{
|
||||
if (requestScript.DeclaredTypes == null || requestScript.DeclaredTypes.Length == 0)
|
||||
return;
|
||||
|
||||
var documentPath = requestScript.DocumentPath;
|
||||
|
||||
foreach (var declaredType in requestScript.DeclaredTypes)
|
||||
{
|
||||
if (ScriptFinder.FindInstanceOfType(declaredType, documentPath, out var go, out var so))
|
||||
{
|
||||
if (go != null)
|
||||
SendGameObject(go);
|
||||
else if (so != null)
|
||||
SendScriptableObject(so);
|
||||
else
|
||||
Serilog.Log.Warning("Invalid instance of type");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendScriptMissing(declaredType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ScriptMissing scriptMissing)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ScriptMissing)");
|
||||
}
|
||||
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.Handshake handshake)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestInternalLog requestInternalLog)
|
||||
{
|
||||
SendInternalLog();
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.InternalLog internalLog)
|
||||
{
|
||||
Logger.ELogger.VsInternalLog = internalLog.LogContent;
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.AnalyticsEvent analyticsEvent)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.AnalyticsEvent)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ErrorReport errorReport)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.ErrorReport)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestVerboseType requestVerboseType)
|
||||
{
|
||||
Serilog.Log.Warning("Unity/Server shouldn't call Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestVerboseType)");
|
||||
}
|
||||
|
||||
void Synchronizer.Model.IProcessor.Process(Synchronizer.Model.RequestLazyLoad requestLazyLoad)
|
||||
{
|
||||
Monitor.LazyLoad(requestLazyLoad.Category);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
11
Assets/Plugins/CodeAssist/Editor/NetMQPublisher.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/NetMQPublisher.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e27a6a4e55657c4469a3397032ed9546
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor/Preferences.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor/Preferences.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a27215493476a2e43b65b286517deb35
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,60 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
//namespace BgTools.PlayerPrefsEditor
|
||||
namespace Meryel.UnityCodeAssist.Editor.Preferences
|
||||
{
|
||||
[System.Serializable]
|
||||
public class PreferenceEntryHolder : ScriptableObject
|
||||
{
|
||||
public List<PreferenceEntry>? userDefList;
|
||||
public List<PreferenceEntry>? unityDefList;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
hideFlags = HideFlags.DontSave;
|
||||
userDefList ??= new List<PreferenceEntry>();
|
||||
unityDefList ??= new List<PreferenceEntry>();
|
||||
}
|
||||
|
||||
public void ClearLists()
|
||||
{
|
||||
userDefList?.Clear();
|
||||
unityDefList?.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class PreferenceEntry
|
||||
{
|
||||
public enum PrefTypes
|
||||
{
|
||||
String = 0,
|
||||
Int = 1,
|
||||
Float = 2
|
||||
}
|
||||
|
||||
public PrefTypes m_typeSelection;
|
||||
public string? m_key;
|
||||
|
||||
// Need diffrend ones for auto type selection of serilizedProerty
|
||||
public string? m_strValue;
|
||||
public int m_intValue;
|
||||
public float m_floatValue;
|
||||
|
||||
public string? ValueAsString()
|
||||
{
|
||||
return m_typeSelection switch
|
||||
{
|
||||
PrefTypes.String => m_strValue,
|
||||
PrefTypes.Int => m_intValue.ToString(),
|
||||
PrefTypes.Float => m_floatValue.ToString(),
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38f9da72011fd244b94cc233de93ac92
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,370 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditorInternal;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor.Preferences
|
||||
{
|
||||
public class PreferenceMonitor
|
||||
{
|
||||
private static readonly Lazy<PreferenceMonitor> _instanceOfPlayerPrefs = new Lazy<PreferenceMonitor>(() => new PreferenceMonitor(true));
|
||||
private static readonly Lazy<PreferenceMonitor> _instanceOfEditorPrefs = new Lazy<PreferenceMonitor>(() => new PreferenceMonitor(false));
|
||||
public static PreferenceMonitor InstanceOfPlayerPrefs => _instanceOfPlayerPrefs.Value;
|
||||
public static PreferenceMonitor InstanceOfEditorPrefs => _instanceOfEditorPrefs.Value;
|
||||
|
||||
//const int Limit = 128;
|
||||
const int Limit = 8192;
|
||||
|
||||
/// <summary>
|
||||
/// PlayerPrefs or EditorPrefs
|
||||
/// </summary>
|
||||
readonly bool isPlayerPrefs;
|
||||
|
||||
#region ErrorValues
|
||||
private readonly int ERROR_VALUE_INT = int.MinValue;
|
||||
private readonly string ERROR_VALUE_STR = "<UCA_ERR_2407201713>";
|
||||
#endregion //ErrorValues
|
||||
|
||||
#pragma warning disable CS0414
|
||||
private static string pathToPrefs = String.Empty;
|
||||
private static string platformPathPrefix = @"~";
|
||||
#pragma warning restore CS0414
|
||||
|
||||
//private string[] userDef;
|
||||
//private string[] unityDef;
|
||||
//private bool showSystemGroup = false;
|
||||
|
||||
private SerializedObject? serializedObject;
|
||||
private ReorderableList? userDefList;
|
||||
private ReorderableList? unityDefList;
|
||||
|
||||
private PreferenceEntryHolder? prefEntryHolder;
|
||||
|
||||
private PreferanceStorageAccessor? entryAccessor;
|
||||
|
||||
|
||||
private bool updateView = false;
|
||||
//private bool monitoring = false;
|
||||
//private bool showLoadingIndicatorOverlay = false;
|
||||
|
||||
|
||||
#if UNITY_EDITOR_LINUX
|
||||
private readonly char[] invalidFilenameChars = { '"', '\\', '*', '/', ':', '<', '>', '?', '|' };
|
||||
#elif UNITY_EDITOR_OSX
|
||||
private readonly char[] invalidFilenameChars = { '$', '%', '&', '\\', '/', ':', '<', '>', '|', '~' };
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
PreferenceMonitor(bool isPlayerPrefs)
|
||||
{
|
||||
this.isPlayerPrefs = isPlayerPrefs;
|
||||
OnEnable();
|
||||
EditorApplication.update += Update;
|
||||
}
|
||||
|
||||
~PreferenceMonitor()
|
||||
{
|
||||
OnDisable();
|
||||
}
|
||||
|
||||
public void Bump()
|
||||
{
|
||||
Serilog.Log.Debug("Bumping preference {IsPlayerPrefs}", isPlayerPrefs);
|
||||
|
||||
RetrieveAndSendKeysAndValues(false);
|
||||
}
|
||||
|
||||
private void RetrieveAndSendKeysAndValues(bool reloadKeys)
|
||||
{
|
||||
string[]? keys = GetKeys(reloadKeys);
|
||||
if (keys == null)
|
||||
return;
|
||||
string[] values = GetKeyValues(reloadKeys, keys, out var stringKeys, out var integerKeys, out var floatKeys, out var booleanKeys);
|
||||
|
||||
if (isPlayerPrefs)
|
||||
NetMQInitializer.Publisher?.SendPlayerPrefs(keys, values, stringKeys, integerKeys, floatKeys);
|
||||
else
|
||||
NetMQInitializer.Publisher?.SendEditorPrefs(keys, values, stringKeys, integerKeys, floatKeys, booleanKeys);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR_WIN
|
||||
if (isPlayerPrefs)
|
||||
pathToPrefs = @"SOFTWARE\Unity\UnityEditor\" + PlayerSettings.companyName + @"\" + PlayerSettings.productName;
|
||||
else
|
||||
pathToPrefs = @"Software\Unity Technologies\Unity Editor 5.x";
|
||||
|
||||
platformPathPrefix = @"<CurrentUser>";
|
||||
entryAccessor = new WindowsPrefStorage(pathToPrefs);
|
||||
#elif UNITY_EDITOR_OSX
|
||||
if (isPlayerPrefs)
|
||||
pathToPrefs = @"Library/Preferences/com." + MakeValidFileName(PlayerSettings.companyName) + "." + MakeValidFileName(PlayerSettings.productName) + ".plist";
|
||||
else
|
||||
pathToPrefs = @"Library/Preferences/com.unity3d.UnityEditor5.x.plist";
|
||||
|
||||
platformPathPrefix = @"~";
|
||||
entryAccessor = new MacPrefStorage(pathToPrefs);
|
||||
//entryAccessor.StartLoadingDelegate = () => { showLoadingIndicatorOverlay = true; };
|
||||
//entryAccessor.StopLoadingDelegate = () => { showLoadingIndicatorOverlay = false; };
|
||||
#elif UNITY_EDITOR_LINUX
|
||||
if (isPlayerPrefs)
|
||||
pathToPrefs = @".config/unity3d/" + MakeValidFileName(PlayerSettings.companyName) + "/" + MakeValidFileName(PlayerSettings.productName) + "/prefs";
|
||||
else
|
||||
pathToPrefs = @".local/share/unity3d/prefs";
|
||||
|
||||
platformPathPrefix = @"~";
|
||||
entryAccessor = new LinuxPrefStorage(pathToPrefs);
|
||||
#else
|
||||
Serilog.Log.Warning("Undefined Unity Editor platform");
|
||||
pathToPrefs = String.Empty;
|
||||
platformPathPrefix = @"~";
|
||||
entryAccessor = null;
|
||||
#endif
|
||||
|
||||
if (entryAccessor != null)
|
||||
{
|
||||
entryAccessor.PrefEntryChangedDelegate = () => { updateView = true; };
|
||||
entryAccessor.StartMonitoring();
|
||||
}
|
||||
}
|
||||
|
||||
// Handel view updates for monitored changes
|
||||
// Necessary to avoid main thread access issue
|
||||
private void Update()
|
||||
{
|
||||
if (updateView)
|
||||
{
|
||||
updateView = false;
|
||||
//PrepareData();
|
||||
//Repaint();
|
||||
|
||||
Serilog.Log.Debug("Updating preference {IsPlayerPrefs}", isPlayerPrefs);
|
||||
|
||||
RetrieveAndSendKeysAndValues(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
entryAccessor?.StopMonitoring();
|
||||
}
|
||||
|
||||
private void InitReorderedList()
|
||||
{
|
||||
if (prefEntryHolder == null)
|
||||
{
|
||||
var tmp = Resources.FindObjectsOfTypeAll<PreferenceEntryHolder>();
|
||||
if (tmp.Length > 0)
|
||||
{
|
||||
prefEntryHolder = tmp[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
prefEntryHolder = ScriptableObject.CreateInstance<PreferenceEntryHolder>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
serializedObject ??= new SerializedObject(prefEntryHolder);
|
||||
|
||||
userDefList = new ReorderableList(serializedObject, serializedObject.FindProperty("userDefList"), false, true, true, true);
|
||||
unityDefList = new ReorderableList(serializedObject, serializedObject.FindProperty("unityDefList"), false, true, false, false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private string[]? GetKeys(bool reloadKeys)
|
||||
{
|
||||
if (entryAccessor == null)
|
||||
{
|
||||
Serilog.Log.Warning($"{nameof(entryAccessor)} is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] keys = entryAccessor.GetKeys(reloadKeys);
|
||||
|
||||
if (keys.Length > Limit)
|
||||
keys = keys.Where(k => !k.StartsWith("unity.") && !k.StartsWith("UnityGraphicsQuality")).Take(Limit).ToArray();
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
string[]? _cachedKeyValues = null;
|
||||
|
||||
string[]? _cachedStringKeys = null;
|
||||
string[]? _cachedIntegerKeys = null;
|
||||
string[]? _cachedFloatKeys = null;
|
||||
string[]? _cachedBooleanKeys = null;
|
||||
|
||||
private string[] GetKeyValues(bool reloadData, string[] keys,
|
||||
out string[] stringKeys, out string[] integerKeys, out string[] floatKeys, out string[] booleanKeys)
|
||||
{
|
||||
if (!reloadData && _cachedKeyValues != null && _cachedKeyValues.Length == keys.Length)
|
||||
{
|
||||
stringKeys = _cachedStringKeys!;
|
||||
integerKeys = _cachedIntegerKeys!;
|
||||
floatKeys = _cachedFloatKeys!;
|
||||
booleanKeys = _cachedBooleanKeys!;
|
||||
return _cachedKeyValues;
|
||||
}
|
||||
|
||||
string[] values = new string[keys.Length];
|
||||
var stringKeyList = new List<string>();
|
||||
var integerKeyList = new List<string>();
|
||||
var floatKeyList = new List<string>();
|
||||
var boolenKeyList = new List<string>();
|
||||
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
var key = keys[i];
|
||||
|
||||
string stringValue;
|
||||
if (isPlayerPrefs)
|
||||
stringValue = PlayerPrefs.GetString(key, ERROR_VALUE_STR);
|
||||
else
|
||||
stringValue = EditorPrefs.GetString(key, ERROR_VALUE_STR);
|
||||
|
||||
if (stringValue != ERROR_VALUE_STR)
|
||||
{
|
||||
values[i] = stringValue;
|
||||
stringKeyList.Add(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
float floatValue;
|
||||
if (isPlayerPrefs)
|
||||
floatValue = PlayerPrefs.GetFloat(key, float.NaN);
|
||||
else
|
||||
floatValue = EditorPrefs.GetFloat(key, float.NaN);
|
||||
|
||||
if (!float.IsNaN(floatValue))
|
||||
{
|
||||
values[i] = floatValue.ToString();
|
||||
floatKeyList.Add(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
int intValue;
|
||||
if (isPlayerPrefs)
|
||||
intValue = PlayerPrefs.GetInt(key, ERROR_VALUE_INT);
|
||||
else
|
||||
intValue = EditorPrefs.GetInt(key, ERROR_VALUE_INT);
|
||||
|
||||
if (intValue != ERROR_VALUE_INT)
|
||||
{
|
||||
values[i] = intValue.ToString();
|
||||
integerKeyList.Add(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool boolValue = false;
|
||||
if (!isPlayerPrefs)
|
||||
{
|
||||
bool boolValueTrue = EditorPrefs.GetBool(key, true);
|
||||
bool boolValueFalse = EditorPrefs.GetBool(key, false);
|
||||
|
||||
boolValue = boolValueFalse;
|
||||
if (boolValueTrue == boolValueFalse)
|
||||
{
|
||||
values[i] = boolValueTrue.ToString();
|
||||
boolenKeyList.Add(key);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
values[i] = string.Empty;
|
||||
if (isPlayerPrefs)
|
||||
{
|
||||
// Keys with ? causing problems, just ignore them
|
||||
if (key.Contains("?"))
|
||||
Serilog.Log.Debug("Invalid {PreferenceType} KEY WITH '?', '{Key}' at {Location}, str:{StringValue}, int:{IntegerValue}, float:{FloatValue}, bool:{BooleanValue}",
|
||||
(isPlayerPrefs ? "PlayerPrefs" : "EditorPrefs"), key, nameof(GetKeyValues),
|
||||
stringValue, intValue, floatValue, boolValue);
|
||||
|
||||
else
|
||||
// EditorPrefs gives error for some keys
|
||||
Serilog.Log.Error("Invalid {PreferenceType} '{Key}' at {Location}, str:{StringValue}, int:{IntegerValue}, float:{FloatValue}, bool:{BooleanValue}",
|
||||
(isPlayerPrefs ? "PlayerPrefs" : "EditorPrefs"), key, nameof(GetKeyValues),
|
||||
stringValue, intValue, floatValue, boolValue);
|
||||
}
|
||||
}
|
||||
|
||||
stringKeys = stringKeyList.ToArray();
|
||||
integerKeys = integerKeyList.ToArray();
|
||||
floatKeys = floatKeyList.ToArray();
|
||||
booleanKeys = boolenKeyList.ToArray();
|
||||
|
||||
_cachedKeyValues = values;
|
||||
|
||||
_cachedStringKeys = stringKeys;
|
||||
_cachedIntegerKeys = integerKeys;
|
||||
_cachedFloatKeys = floatKeys;
|
||||
_cachedBooleanKeys = booleanKeys;
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private void LoadKeys(out string[]? userDef, out string[]? unityDef, bool reloadKeys)
|
||||
{
|
||||
if(entryAccessor == null)
|
||||
{
|
||||
userDef = null;
|
||||
unityDef = null;
|
||||
return;
|
||||
}
|
||||
|
||||
string[] keys = entryAccessor.GetKeys(reloadKeys);
|
||||
|
||||
//keys.ToList().ForEach( e => { Debug.Log(e); } );
|
||||
|
||||
// Seperate keys int unity defined and user defined
|
||||
Dictionary<bool, List<string>> groups = keys
|
||||
.GroupBy((key) => key.StartsWith("unity.") || key.StartsWith("UnityGraphicsQuality"))
|
||||
.ToDictionary((g) => g.Key, (g) => g.ToList());
|
||||
|
||||
unityDef = (groups.ContainsKey(true)) ? groups[true].ToArray() : new string[0];
|
||||
userDef = (groups.ContainsKey(false)) ? groups[false].ToArray() : new string[0];
|
||||
}
|
||||
|
||||
|
||||
#if (UNITY_EDITOR_LINUX || UNITY_EDITOR_OSX)
|
||||
private string MakeValidFileName(string unsafeFileName)
|
||||
{
|
||||
string normalizedFileName = unsafeFileName.Trim().Normalize(NormalizationForm.FormD);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
// We need to use a TextElementEmumerator in order to support UTF16 characters that may take up more than one char(case 1169358)
|
||||
TextElementEnumerator charEnum = StringInfo.GetTextElementEnumerator(normalizedFileName);
|
||||
while (charEnum.MoveNext())
|
||||
{
|
||||
string c = charEnum.GetTextElement();
|
||||
if (c.Length == 1 && invalidFilenameChars.Contains(c[0]))
|
||||
{
|
||||
stringBuilder.Append('_');
|
||||
continue;
|
||||
}
|
||||
UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c, 0);
|
||||
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7885cbf1aab77214c8bbcf789440022d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,287 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
#if UNITY_EDITOR_WIN
|
||||
using Microsoft.Win32;
|
||||
using System.Text;
|
||||
#elif UNITY_EDITOR_OSX
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
#elif UNITY_EDITOR_LINUX
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
#endif
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
//namespace BgTools.PlayerPrefsEditor
|
||||
namespace Meryel.UnityCodeAssist.Editor.Preferences
|
||||
{
|
||||
public abstract class PreferanceStorageAccessor
|
||||
{
|
||||
protected string prefPath;
|
||||
protected string[] cachedData = new string[0];
|
||||
|
||||
protected abstract void FetchKeysFromSystem();
|
||||
|
||||
protected PreferanceStorageAccessor(string pathToPrefs)
|
||||
{
|
||||
prefPath = pathToPrefs;
|
||||
}
|
||||
|
||||
public string[] GetKeys(bool reloadData = true)
|
||||
{
|
||||
if (reloadData || cachedData.Length == 0)
|
||||
{
|
||||
FetchKeysFromSystem();
|
||||
}
|
||||
|
||||
return cachedData;
|
||||
}
|
||||
|
||||
public Action? PrefEntryChangedDelegate;
|
||||
protected bool ignoreNextChange = false;
|
||||
|
||||
public void IgnoreNextChange()
|
||||
{
|
||||
ignoreNextChange = true;
|
||||
}
|
||||
|
||||
protected virtual void OnPrefEntryChanged()
|
||||
{
|
||||
if (ignoreNextChange)
|
||||
{
|
||||
ignoreNextChange = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PrefEntryChangedDelegate?.Invoke();
|
||||
}
|
||||
|
||||
public Action? StartLoadingDelegate;
|
||||
public Action? StopLoadingDelegate;
|
||||
|
||||
public abstract void StartMonitoring();
|
||||
public abstract void StopMonitoring();
|
||||
public abstract bool IsMonitoring();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR_WIN
|
||||
|
||||
public class WindowsPrefStorage : PreferanceStorageAccessor
|
||||
{
|
||||
readonly RegistryMonitor monitor;
|
||||
|
||||
public WindowsPrefStorage(string pathToPrefs) : base(pathToPrefs)
|
||||
{
|
||||
monitor = new RegistryMonitor(RegistryHive.CurrentUser, prefPath);
|
||||
monitor.RegChanged += new EventHandler(OnRegChanged);
|
||||
}
|
||||
|
||||
private void OnRegChanged(object sender, EventArgs e)
|
||||
{
|
||||
OnPrefEntryChanged();
|
||||
}
|
||||
|
||||
protected override void FetchKeysFromSystem()
|
||||
{
|
||||
cachedData = new string[0];
|
||||
|
||||
using (RegistryKey rootKey = Registry.CurrentUser.OpenSubKey(prefPath))
|
||||
{
|
||||
if (rootKey != null)
|
||||
{
|
||||
cachedData = rootKey.GetValueNames();
|
||||
rootKey.Close();
|
||||
}
|
||||
}
|
||||
|
||||
// Clean <key>_h3320113488 nameing
|
||||
//cachedData = cachedData.Select((key) => { return key.Substring(0, key.LastIndexOf("_h", StringComparison.Ordinal)); }).ToArray();
|
||||
for (int i = 0; i < cachedData.Length; i++)
|
||||
{
|
||||
var indexOfSuffix = cachedData[i].LastIndexOf("_h", StringComparison.Ordinal);
|
||||
if (indexOfSuffix >= 0)
|
||||
cachedData[i] = cachedData[i].Substring(0, indexOfSuffix);
|
||||
}
|
||||
|
||||
EncodeAnsiInPlace();
|
||||
}
|
||||
|
||||
public override void StartMonitoring()
|
||||
{
|
||||
monitor.Start();
|
||||
}
|
||||
|
||||
public override void StopMonitoring()
|
||||
{
|
||||
monitor.Stop();
|
||||
}
|
||||
|
||||
public override bool IsMonitoring()
|
||||
{
|
||||
return monitor.IsMonitoring;
|
||||
}
|
||||
|
||||
private void EncodeAnsiInPlace()
|
||||
{
|
||||
Encoding utf8 = Encoding.UTF8;
|
||||
Encoding ansi = Encoding.GetEncoding(1252);
|
||||
|
||||
for (int i = 0; i < cachedData.Length; i++)
|
||||
{
|
||||
cachedData[i] = utf8.GetString(ansi.GetBytes(cachedData[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif UNITY_EDITOR_LINUX
|
||||
|
||||
public class LinuxPrefStorage : PreferanceStorageAccessor
|
||||
{
|
||||
readonly FileSystemWatcher fileWatcher;
|
||||
|
||||
public LinuxPrefStorage(string pathToPrefs) : base(Path.Combine(Environment.GetEnvironmentVariable("HOME"), pathToPrefs))
|
||||
{
|
||||
fileWatcher = new FileSystemWatcher
|
||||
{
|
||||
Path = Path.GetDirectoryName(prefPath),
|
||||
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite,
|
||||
Filter = "prefs"
|
||||
};
|
||||
|
||||
fileWatcher.Changed += OnWatchedFileChanged;
|
||||
}
|
||||
|
||||
protected override void FetchKeysFromSystem()
|
||||
{
|
||||
cachedData = new string[0];
|
||||
|
||||
if (File.Exists(prefPath))
|
||||
{
|
||||
XmlReaderSettings settings = new XmlReaderSettings();
|
||||
XmlReader reader = XmlReader.Create(prefPath, settings);
|
||||
|
||||
XDocument doc = XDocument.Load(reader);
|
||||
|
||||
cachedData = doc.Element("unity_prefs").Elements().Select((e) => e.Attribute("name").Value).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartMonitoring()
|
||||
{
|
||||
fileWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
public override void StopMonitoring()
|
||||
{
|
||||
fileWatcher.EnableRaisingEvents = false;
|
||||
}
|
||||
|
||||
public override bool IsMonitoring()
|
||||
{
|
||||
return fileWatcher.EnableRaisingEvents;
|
||||
}
|
||||
|
||||
private void OnWatchedFileChanged(object source, FileSystemEventArgs e)
|
||||
{
|
||||
OnPrefEntryChanged();
|
||||
}
|
||||
}
|
||||
|
||||
#elif UNITY_EDITOR_OSX
|
||||
|
||||
public class MacPrefStorage : PreferanceStorageAccessor
|
||||
{
|
||||
private readonly FileSystemWatcher fileWatcher;
|
||||
private readonly DirectoryInfo prefsDirInfo;
|
||||
private readonly String prefsFileNameWithoutExtension;
|
||||
|
||||
public MacPrefStorage(string pathToPrefs) : base(Path.Combine(Environment.GetEnvironmentVariable("HOME"), pathToPrefs))
|
||||
{
|
||||
prefsDirInfo = new DirectoryInfo(Path.GetDirectoryName(prefPath));
|
||||
prefsFileNameWithoutExtension = Path.GetFileNameWithoutExtension(prefPath);
|
||||
|
||||
fileWatcher = new FileSystemWatcher
|
||||
{
|
||||
Path = Path.GetDirectoryName(prefPath),
|
||||
NotifyFilter = NotifyFilters.LastWrite,
|
||||
Filter = Path.GetFileName(prefPath)
|
||||
};
|
||||
|
||||
// MAC delete the old and create a new file instead of updating
|
||||
fileWatcher.Created += OnWatchedFileChanged;
|
||||
}
|
||||
|
||||
protected override void FetchKeysFromSystem()
|
||||
{
|
||||
// Workaround to avoid incomplete tmp phase from MAC OS
|
||||
foreach (FileInfo info in prefsDirInfo.GetFiles())
|
||||
{
|
||||
// Check if tmp PlayerPrefs file exist
|
||||
if (info.FullName.Contains(prefsFileNameWithoutExtension) && !info.FullName.EndsWith(".plist"))
|
||||
{
|
||||
StartLoadingDelegate?.Invoke();
|
||||
return;
|
||||
}
|
||||
}
|
||||
StopLoadingDelegate?.Invoke();
|
||||
|
||||
cachedData = new string[0];
|
||||
|
||||
if (File.Exists(prefPath))
|
||||
{
|
||||
string fixedPrefsPath = prefPath.Replace("\"", "\\\"").Replace("'", "\\'").Replace("`", "\\`");
|
||||
var cmdStr = string.Format(@"-p '{0}'", fixedPrefsPath);
|
||||
|
||||
string stdOut = String.Empty;
|
||||
string errOut = String.Empty;
|
||||
|
||||
var process = new System.Diagnostics.Process();
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
process.StartInfo.FileName = "plutil";
|
||||
process.StartInfo.Arguments = cmdStr;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.OutputDataReceived += new DataReceivedEventHandler((sender, evt) => { stdOut += evt.Data + "\n"; });
|
||||
process.ErrorDataReceived += new DataReceivedEventHandler((sender, evt) => { errOut += evt.Data + "\n"; });
|
||||
|
||||
process.Start();
|
||||
|
||||
process.BeginOutputReadLine();
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
MatchCollection matches = Regex.Matches(stdOut, @"(?: "")(.*)(?:"" =>.*)");
|
||||
cachedData = matches.Cast<Match>().Select((e) => e.Groups[1].Value).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartMonitoring()
|
||||
{
|
||||
fileWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
public override void StopMonitoring()
|
||||
{
|
||||
fileWatcher.EnableRaisingEvents = false;
|
||||
}
|
||||
|
||||
public override bool IsMonitoring()
|
||||
{
|
||||
return fileWatcher.EnableRaisingEvents;
|
||||
}
|
||||
|
||||
private void OnWatchedFileChanged(object source, FileSystemEventArgs e)
|
||||
{
|
||||
OnPrefEntryChanged();
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5a10351133ed64a488d6be3043f5402a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
339
Assets/Plugins/CodeAssist/Editor/Preferences/RegistryMonitor.cs
Normal file
339
Assets/Plugins/CodeAssist/Editor/Preferences/RegistryMonitor.cs
Normal file
|
@ -0,0 +1,339 @@
|
|||
|
||||
/*
|
||||
* Thanks to gr0ss for the inspiration.
|
||||
*
|
||||
* https://github.com/gr0ss/RegistryMonitor
|
||||
*
|
||||
* 11/08/2019
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32;
|
||||
|
||||
//namespace BgTools.PlayerPrefsEditor
|
||||
namespace Meryel.UnityCodeAssist.Editor.Preferences
|
||||
{
|
||||
public class RegistryMonitor : IDisposable
|
||||
{
|
||||
#region P/Invoke
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int RegOpenKeyEx(IntPtr hKey, string subKey, uint options, int samDesired, out IntPtr phkResult);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern int RegNotifyChangeKeyValue(IntPtr hKey, bool bWatchSubtree, RegChangeNotifyFilter dwNotifyFilter, IntPtr hEvent, bool fAsynchronous);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
private static extern int RegCloseKey(IntPtr hKey);
|
||||
|
||||
private const int KEY_QUERY_VALUE = 0x0001;
|
||||
private const int KEY_NOTIFY = 0x0010;
|
||||
private const int STANDARD_RIGHTS_READ = 0x00020000;
|
||||
|
||||
private static readonly IntPtr HKEY_CLASSES_ROOT = new IntPtr(unchecked((int)0x80000000));
|
||||
private static readonly IntPtr HKEY_CURRENT_USER = new IntPtr(unchecked((int)0x80000001));
|
||||
private static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
|
||||
private static readonly IntPtr HKEY_USERS = new IntPtr(unchecked((int)0x80000003));
|
||||
private static readonly IntPtr HKEY_PERFORMANCE_DATA = new IntPtr(unchecked((int)0x80000004));
|
||||
private static readonly IntPtr HKEY_CURRENT_CONFIG = new IntPtr(unchecked((int)0x80000005));
|
||||
private static readonly IntPtr HKEY_DYN_DATA = new IntPtr(unchecked((int)0x80000006));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handling
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the specified registry key has changed.
|
||||
/// </summary>
|
||||
public event EventHandler RegChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="RegChanged"/> event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// <b>OnRegChanged</b> is called when the specified registry key has changed.
|
||||
/// </p>
|
||||
/// <note type="inheritinfo">
|
||||
/// When overriding <see cref="OnRegChanged"/> in a derived class, be sure to call
|
||||
/// the base class's <see cref="OnRegChanged"/> method.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
protected virtual void OnRegChanged()
|
||||
{
|
||||
RegChanged?.Invoke(this, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the access to the registry fails.
|
||||
/// </summary>
|
||||
public event ErrorEventHandler Error;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="Error"/> event.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="Exception"/> which occured while watching the registry.</param>
|
||||
/// <remarks>
|
||||
/// <p>
|
||||
/// <b>OnError</b> is called when an exception occurs while watching the registry.
|
||||
/// </p>
|
||||
/// <note type="inheritinfo">
|
||||
/// When overriding <see cref="OnError"/> in a derived class, be sure to call
|
||||
/// the base class's <see cref="OnError"/> method.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
protected virtual void OnError(Exception e)
|
||||
{
|
||||
Error?.Invoke(this, new ErrorEventArgs(e));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private member variables
|
||||
|
||||
private IntPtr _registryHive;
|
||||
private string _registrySubName;
|
||||
private readonly object _threadLock = new object();
|
||||
private Thread _thread;
|
||||
private bool _disposed = false;
|
||||
private readonly ManualResetEvent _eventTerminate = new ManualResetEvent(false);
|
||||
|
||||
private RegChangeNotifyFilter _regFilter = RegChangeNotifyFilter.Key | RegChangeNotifyFilter.Attribute | RegChangeNotifyFilter.Value | RegChangeNotifyFilter.Security;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegistryMonitor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registryKey">The registry key to monitor.</param>
|
||||
public RegistryMonitor(RegistryKey registryKey)
|
||||
{
|
||||
InitRegistryKey(registryKey.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegistryMonitor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
public RegistryMonitor(string name)
|
||||
{
|
||||
if (name == null || name.Length == 0)
|
||||
throw new ArgumentNullException("name");
|
||||
|
||||
InitRegistryKey(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegistryMonitor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registryHive">The registry hive.</param>
|
||||
/// <param name="subKey">The sub key.</param>
|
||||
public RegistryMonitor(RegistryHive registryHive, string subKey)
|
||||
{
|
||||
InitRegistryKey(registryHive, subKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this object.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="RegChangeNotifyFilter">RegChangeNotifyFilter</see>.
|
||||
/// </summary>
|
||||
public RegChangeNotifyFilter RegChangeNotifyFilter
|
||||
{
|
||||
get { return _regFilter; }
|
||||
set
|
||||
{
|
||||
lock (_threadLock)
|
||||
{
|
||||
if (IsMonitoring)
|
||||
throw new InvalidOperationException("Monitoring thread is already running");
|
||||
|
||||
_regFilter = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Initialization
|
||||
|
||||
private void InitRegistryKey(RegistryHive hive, string name)
|
||||
{
|
||||
_registryHive = hive switch
|
||||
{
|
||||
RegistryHive.ClassesRoot => HKEY_CLASSES_ROOT,
|
||||
RegistryHive.CurrentConfig => HKEY_CURRENT_CONFIG,
|
||||
RegistryHive.CurrentUser => HKEY_CURRENT_USER,
|
||||
RegistryHive.DynData => HKEY_DYN_DATA,
|
||||
RegistryHive.LocalMachine => HKEY_LOCAL_MACHINE,
|
||||
RegistryHive.PerformanceData => HKEY_PERFORMANCE_DATA,
|
||||
RegistryHive.Users => HKEY_USERS,
|
||||
_ => throw new InvalidEnumArgumentException("hive", (int)hive, typeof(RegistryHive)),
|
||||
};
|
||||
_registrySubName = name;
|
||||
}
|
||||
|
||||
private void InitRegistryKey(string name)
|
||||
{
|
||||
string[] nameParts = name.Split('\\');
|
||||
|
||||
switch (nameParts[0])
|
||||
{
|
||||
case "HKEY_CLASSES_ROOT":
|
||||
case "HKCR":
|
||||
_registryHive = HKEY_CLASSES_ROOT;
|
||||
break;
|
||||
|
||||
case "HKEY_CURRENT_USER":
|
||||
case "HKCU":
|
||||
_registryHive = HKEY_CURRENT_USER;
|
||||
break;
|
||||
|
||||
case "HKEY_LOCAL_MACHINE":
|
||||
case "HKLM":
|
||||
_registryHive = HKEY_LOCAL_MACHINE;
|
||||
break;
|
||||
|
||||
case "HKEY_USERS":
|
||||
_registryHive = HKEY_USERS;
|
||||
break;
|
||||
|
||||
case "HKEY_CURRENT_CONFIG":
|
||||
_registryHive = HKEY_CURRENT_CONFIG;
|
||||
break;
|
||||
|
||||
default:
|
||||
_registryHive = IntPtr.Zero;
|
||||
throw new ArgumentException("The registry hive '" + nameParts[0] + "' is not supported", "value");
|
||||
}
|
||||
|
||||
_registrySubName = String.Join("\\", nameParts, 1, nameParts.Length - 1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// <b>true</b> if this <see cref="RegistryMonitor"/> object is currently monitoring;
|
||||
/// otherwise, <b>false</b>.
|
||||
/// </summary>
|
||||
public bool IsMonitoring
|
||||
{
|
||||
get { return _thread != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start monitoring.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(null, "This instance is already disposed");
|
||||
|
||||
lock (_threadLock)
|
||||
{
|
||||
if (!IsMonitoring)
|
||||
{
|
||||
_eventTerminate.Reset();
|
||||
_thread = new Thread(new ThreadStart(MonitorThread)) { IsBackground = true };
|
||||
_thread.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the monitoring thread.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(null, "This instance is already disposed");
|
||||
|
||||
lock (_threadLock)
|
||||
{
|
||||
Thread thread = _thread;
|
||||
if (thread != null)
|
||||
{
|
||||
_eventTerminate.Set();
|
||||
thread.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MonitorThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
ThreadLoop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OnError(e);
|
||||
}
|
||||
_thread = null;
|
||||
}
|
||||
|
||||
private void ThreadLoop()
|
||||
{
|
||||
int result = RegOpenKeyEx(_registryHive, _registrySubName, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_NOTIFY, out IntPtr registryKey);
|
||||
if (result != 0)
|
||||
{
|
||||
throw new Win32Exception(result);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AutoResetEvent _eventNotify = new AutoResetEvent(false);
|
||||
WaitHandle[] waitHandles = new WaitHandle[] { _eventNotify, _eventTerminate };
|
||||
while (!_eventTerminate.WaitOne(0, true))
|
||||
{
|
||||
result = RegNotifyChangeKeyValue(registryKey, true, _regFilter, _eventNotify.SafeWaitHandle.DangerousGetHandle(), true);
|
||||
if (result != 0)
|
||||
{
|
||||
throw new Win32Exception(result);
|
||||
}
|
||||
|
||||
if (WaitHandle.WaitAny(waitHandles) == 0)
|
||||
{
|
||||
OnRegChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (registryKey != IntPtr.Zero)
|
||||
{
|
||||
RegCloseKey(registryKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filter for notifications reported by <see cref="RegistryMonitor"/>.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum RegChangeNotifyFilter
|
||||
{
|
||||
/// <summary>Notify the caller if a subkey is added or deleted.</summary>
|
||||
Key = 1,
|
||||
/// <summary>Notify the caller of changes to the attributes of the key,
|
||||
/// such as the security descriptor information.</summary>
|
||||
Attribute = 2,
|
||||
/// <summary>Notify the caller of changes to a value of the key. This can
|
||||
/// include adding or deleting a value, or changing an existing value.</summary>
|
||||
Value = 4,
|
||||
/// <summary>Notify the caller of changes to the security descriptor
|
||||
/// of the key.</summary>
|
||||
Security = 8,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 231ce51d1620ff843ba99ae307c881e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
307
Assets/Plugins/CodeAssist/Editor/ScriptFinder.cs
Normal file
307
Assets/Plugins/CodeAssist/Editor/ScriptFinder.cs
Normal file
|
@ -0,0 +1,307 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
|
||||
public class ScriptFinder //: MonoBehaviour
|
||||
{
|
||||
|
||||
static Type? GetType123(string typeName)
|
||||
{
|
||||
//**--
|
||||
//**--
|
||||
/*
|
||||
* for performance,
|
||||
* check assembly-csharp, assembly-csharp-editor, assembly-csharp-first-pass,assembly-csharp-editor-first-pass
|
||||
* first, (then maybe asmdef dlls), then check mscorlib and other referenced dlls
|
||||
*/
|
||||
|
||||
|
||||
//**--use typecache???
|
||||
//TypeCache
|
||||
|
||||
//**--check this again
|
||||
//https://github.com/Unity-Technologies/SuperScience/blob/main/Editor/GlobalNamespaceWatcher.cs
|
||||
|
||||
// Try Type.GetType() first. This will work with types defined
|
||||
// by the Mono runtime, in the same assembly as the caller, etc.
|
||||
Type type = Type.GetType(typeName);
|
||||
|
||||
// If it worked, then we're done here
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
// Attempt to search for type on the loaded assemblies
|
||||
Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (Assembly assembly in currentAssemblies)
|
||||
{
|
||||
type = assembly.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
// If we still haven't found the proper type, we can enumerate all of the
|
||||
// loaded assemblies and see if any of them define the type
|
||||
var currentAssembly = Assembly.GetExecutingAssembly();
|
||||
var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
|
||||
foreach (var assemblyName in referencedAssemblies)
|
||||
{
|
||||
// Load the referenced assembly
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
if (assembly != null)
|
||||
{
|
||||
// See if that assembly defines the named type
|
||||
type = assembly.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The type just couldn't be found...
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool FindInstanceOfType(string typeName, string docPath, out GameObject? gameObjectInstanceOfType, out ScriptableObject? scriptableObjectInstanceOfType)
|
||||
{
|
||||
gameObjectInstanceOfType = null;
|
||||
scriptableObjectInstanceOfType = null;
|
||||
|
||||
var type = GetType123(typeName);
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
// Possibly a class has been created in Visual Studio, and these changes are not reflected in Unity domain yet
|
||||
// We can force Unity to recompile and get the type, but since there will be no instance of that type, it won't be of any use, will be just a performance burden
|
||||
Serilog.Log.Debug("{Type} type couldn't be found", typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var obj = GetObjectOfType(type, out var requestVerboseType);
|
||||
if (requestVerboseType)
|
||||
NetMQInitializer.Publisher?.SendRequestVerboseType(typeName, docPath);
|
||||
|
||||
if (obj != null && obj is GameObject go)
|
||||
{
|
||||
gameObjectInstanceOfType = go;
|
||||
return true;
|
||||
}
|
||||
else if (obj != null && obj is ScriptableObject so)
|
||||
{
|
||||
scriptableObjectInstanceOfType = so;
|
||||
return true;
|
||||
}
|
||||
|
||||
Serilog.Log.Debug("Instance of {Type} type couldn't be found", typeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
static UnityEngine.Object? GetObjectOfType(Type type, out bool requestVerboseType)
|
||||
{
|
||||
requestVerboseType = false;
|
||||
var isMonoBehaviour = type.IsSubclassOf(typeof(MonoBehaviour));
|
||||
var isScriptableObject = type.IsSubclassOf(typeof(ScriptableObject));
|
||||
|
||||
if (!isMonoBehaviour && !isScriptableObject)
|
||||
{
|
||||
// Possibly a class's base class changed from none to MonoBehaviour in Visual Studio, and these changes are not reflected in Unity domain yet
|
||||
// We can force Unity to recompile and get the type correctly, but since there will be no instance of that type, it won't be of any use, will be just a performance burden
|
||||
Serilog.Log.Debug("{Type} is not a valid Unity object", type.ToString());
|
||||
//requestVerboseType = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
UnityEngine.Object? obj;
|
||||
|
||||
obj = getObjectToSend(Selection.activeGameObject, type);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
|
||||
|
||||
obj = getObjectToSend(Selection.activeTransform, type);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
|
||||
|
||||
obj = getObjectToSend(Selection.activeObject, type);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
|
||||
|
||||
//**--check source code of this, for sorting
|
||||
var filteredArray = Selection.GetFiltered(type, SelectionMode.Unfiltered);
|
||||
if (filteredArray != null)
|
||||
{
|
||||
//**--sort
|
||||
foreach (var filtered in filteredArray)
|
||||
{
|
||||
obj = getObjectToSend(filtered, type);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**--rest can be slow, try avoiding them, make own db etc
|
||||
//**--can add a stop-wacher and add warning if slow as well
|
||||
//**--can also cache the result
|
||||
|
||||
try
|
||||
{
|
||||
// UnityEngine.Object.FindObjectOfType is deprecated in new versions of Unity
|
||||
#if UNITY_2022_3 || UNITY_2023_1_OR_NEWER
|
||||
// Object.FindAnyObjectOfType doesn't return Assets (for example meshes, textures, or prefabs), or inactive objects. It also doesn't return objects that have HideFlags.DontSave set.
|
||||
obj = UnityEngine.Object.FindAnyObjectByType(type);
|
||||
#else
|
||||
// Object.FindObjectOfType will not return Assets (meshes, textures, prefabs, ...) or inactive objects. It will not return an object that has HideFlags.DontSave set.
|
||||
obj = UnityEngine.Object.FindObjectOfType(type);
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Serilog.Log.Warning(ex, "FindObjectOfType/FindAnyObjectByType failed for {Type}, mb:{isMB}, so:{isSO}", type.ToString(), isMonoBehaviour, isScriptableObject);
|
||||
}
|
||||
|
||||
obj = getObjectToSend(obj, type);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
|
||||
UnityEngine.Object[]? arr = null;
|
||||
try
|
||||
{
|
||||
// This function can return any type of Unity object that is loaded, including game objects, prefabs, materials, meshes, textures, etc.
|
||||
// Contrary to Object.FindObjectsOfType this function will also list disabled objects.
|
||||
arr = Resources.FindObjectsOfTypeAll(type);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//var isMonoBehaviour = type.IsSubclassOf(typeof(MonoBehaviour));
|
||||
//var isScriptableObject = type.IsSubclassOf(typeof(ScriptableObject));
|
||||
Serilog.Log.Warning(ex, "FindObjectsOfTypeAll failed for {Type}, mb:{isMB}, so:{isSO}", type.ToString(), isMonoBehaviour, isScriptableObject);
|
||||
}
|
||||
|
||||
if (arr != null)
|
||||
{
|
||||
//**--sort
|
||||
foreach (var item in arr)
|
||||
{
|
||||
obj = getObjectToSend(item, type);
|
||||
if (obj != null)
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
|
||||
|
||||
static UnityEngine.Object? getObjectToSend(UnityEngine.Object? obj, Type type)
|
||||
{
|
||||
if (obj == null || !obj)
|
||||
return null;
|
||||
|
||||
if (obj is GameObject go)
|
||||
{
|
||||
if (!go)
|
||||
return null;
|
||||
if (isTypeComponent(type) && go.GetComponent(type) != null)
|
||||
return go;
|
||||
}
|
||||
else if (obj is Transform transform)
|
||||
{
|
||||
go = transform.gameObject;
|
||||
if (!go)
|
||||
return null;
|
||||
if (isTypeComponent(type) && go.GetComponent(type) != null)
|
||||
return go;
|
||||
}
|
||||
else if (obj is Component comp)
|
||||
{
|
||||
go = comp.gameObject;
|
||||
if (!go)
|
||||
return null;
|
||||
else
|
||||
return go;
|
||||
}
|
||||
else if (obj is ScriptableObject so)
|
||||
{
|
||||
if (!so)
|
||||
return null;
|
||||
else
|
||||
return so;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool isTypeComponent(Type type)
|
||||
{
|
||||
var componentType = typeof(Component);//**--cache these types
|
||||
if (type == componentType || type.IsSubclassOf(componentType))
|
||||
return true;
|
||||
|
||||
// MonoBehaviour is Component, so below is unnecessary
|
||||
//var monoBehaviourType = typeof(MonoBehaviour);
|
||||
//if (type == monoBehaviourType || type.IsSubclassOf(monoBehaviourType))
|
||||
// return true;
|
||||
|
||||
//else if(type is interface)//**--
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void DENEMEEEE()
|
||||
{
|
||||
//UnityEditor.SceneManagement.EditorSceneManager.all
|
||||
//AssetDatabase.get
|
||||
|
||||
foreach (var sceneGUID in AssetDatabase.FindAssets("t:Scene", new string[] { "Assets" }))
|
||||
{
|
||||
var scenePath = AssetDatabase.GUIDToAssetPath(sceneGUID);
|
||||
Debug.Log("scenePath: " + scenePath);
|
||||
|
||||
//EditorSceneManager.OpenScene(scenePath);
|
||||
//var scene = EditorSceneManager.GetActiveScene();
|
||||
}
|
||||
|
||||
var assets = AssetDatabase.FindAssets("Deneme_OtherScene");
|
||||
Debug.Log("Assets: " + assets.Length);
|
||||
|
||||
foreach (var assetGuid in assets)
|
||||
{
|
||||
var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid);
|
||||
Debug.Log("Asset: " + assetGuid + " " + assetPath);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetActiveGameObject(out GameObject activeGameObject)
|
||||
{
|
||||
activeGameObject = Selection.activeGameObject;
|
||||
return activeGameObject ? true : false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/ScriptFinder.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/ScriptFinder.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8633a6fdc230b446985c424ba228a05
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
81
Assets/Plugins/CodeAssist/Editor/StatusWindow.cs
Normal file
81
Assets/Plugins/CodeAssist/Editor/StatusWindow.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
#nullable enable
|
||||
|
||||
|
||||
namespace Meryel.UnityCodeAssist.Editor
|
||||
{
|
||||
public class StatusWindow : EditorWindow
|
||||
{
|
||||
GUIStyle? styleLabel;
|
||||
|
||||
public static void Display()
|
||||
{
|
||||
// Get existing open window or if none, make a new one:
|
||||
var window = GetWindow<StatusWindow>();
|
||||
window.Show();
|
||||
|
||||
NetMQInitializer.Publisher?.SendConnectionInfo();
|
||||
|
||||
Serilog.Log.Debug("Displaying status window");
|
||||
|
||||
NetMQInitializer.Publisher?.SendAnalyticsEvent("Gui", "StatusWindow_Display");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
//**--icon
|
||||
//var icon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Sprites/Gear.png");
|
||||
//titleContent = new GUIContent("Code Assist", icon);
|
||||
titleContent = new GUIContent(Assister.Title);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
var hasAnyClient = NetMQInitializer.Publisher?.clients.Any() == true;
|
||||
|
||||
styleLabel ??= new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
wordWrap = true,
|
||||
alignment = TextAnchor.MiddleLeft,
|
||||
};
|
||||
|
||||
if (hasAnyClient)
|
||||
{
|
||||
EditorGUILayout.LabelField($"Code Assist is working!", styleLabel, GUILayout.ExpandWidth(true));
|
||||
|
||||
foreach (var client in NetMQInitializer.Publisher!.clients)
|
||||
{
|
||||
EditorGUILayout.LabelField($"Connected to {client.ContactInfo}", styleLabel, GUILayout.ExpandWidth(true));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField($"Code Assist isn't working!", styleLabel, GUILayout.ExpandWidth(true));
|
||||
|
||||
EditorGUILayout.LabelField($"No IDE found", styleLabel, GUILayout.ExpandWidth(true));
|
||||
}
|
||||
|
||||
#if MERYEL_UCA_LITE_VERSION
|
||||
|
||||
EditorGUILayout.LabelField($"", styleLabel, GUILayout.ExpandWidth(true));
|
||||
EditorGUILayout.LabelField($"This is the lite version of Code Assist with limited features.", styleLabel, GUILayout.ExpandWidth(true));
|
||||
EditorGUILayout.LabelField($"To unlock all of the features, get the full version.", styleLabel, GUILayout.ExpandWidth(true));
|
||||
|
||||
if (GUILayout.Button("Get full version"))
|
||||
{
|
||||
Application.OpenURL("http://u3d.as/2N2H");
|
||||
}
|
||||
|
||||
#endif // MERYEL_UCA_LITE_VERSION
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/StatusWindow.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/StatusWindow.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: deeb8a5dd8f358c48aaaf8edc44efa59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Plugins/CodeAssist/Editor/TinyJson.meta
Normal file
8
Assets/Plugins/CodeAssist/Editor/TinyJson.meta
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b66a6756b1d4b2c49b08193ba0d4551a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
376
Assets/Plugins/CodeAssist/Editor/TinyJson/JsonParser.cs
Normal file
376
Assets/Plugins/CodeAssist/Editor/TinyJson/JsonParser.cs
Normal file
|
@ -0,0 +1,376 @@
|
|||
// copied from
|
||||
// https://github.com/zanders3/json/blob/master/src/JSONParser.cs
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
//namespace TinyJson
|
||||
namespace Meryel.UnityCodeAssist.Editor.TinyJson
|
||||
{
|
||||
// Really simple JSON parser in ~300 lines
|
||||
// - Attempts to parse JSON files with minimal GC allocation
|
||||
// - Nice and simple "[1,2,3]".FromJson<List<int>>() API
|
||||
// - Classes and structs can be parsed too!
|
||||
// class Foo { public int Value; }
|
||||
// "{\"Value\":10}".FromJson<Foo>()
|
||||
// - Can parse JSON without type information into Dictionary<string,object> and List<object> e.g.
|
||||
// "[1,2,3]".FromJson<object>().GetType() == typeof(List<object>)
|
||||
// "{\"Value\":10}".FromJson<object>().GetType() == typeof(Dictionary<string,object>)
|
||||
// - No JIT Emit support to support AOT compilation on iOS
|
||||
// - Attempts are made to NOT throw an exception if the JSON is corrupted or invalid: returns null instead.
|
||||
// - Only public fields and property setters on classes/structs will be written to
|
||||
//
|
||||
// Limitations:
|
||||
// - No JIT Emit support to parse structures quickly
|
||||
// - Limited to parsing <2GB JSON files (due to int.MaxValue)
|
||||
// - Parsing of abstract classes or interfaces is NOT supported and will throw an exception.
|
||||
public static class JsonParser
|
||||
{
|
||||
[ThreadStatic] static Stack<List<string>> splitArrayPool;
|
||||
[ThreadStatic] static StringBuilder stringBuilder;
|
||||
[ThreadStatic] static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;
|
||||
[ThreadStatic] static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;
|
||||
|
||||
//public static T FromJson<T>(this string json)
|
||||
public static T FromJson<T>(string json)
|
||||
{
|
||||
// Initialize, if needed, the ThreadStatic variables
|
||||
propertyInfoCache ??= new Dictionary<Type, Dictionary<string, PropertyInfo>>();
|
||||
fieldInfoCache ??= new Dictionary<Type, Dictionary<string, FieldInfo>>();
|
||||
stringBuilder ??= new StringBuilder();
|
||||
splitArrayPool ??= new Stack<List<string>>();
|
||||
|
||||
//Remove all whitespace not within strings to make parsing simpler
|
||||
stringBuilder.Length = 0;
|
||||
for (int i = 0; i < json.Length; i++)
|
||||
{
|
||||
char c = json[i];
|
||||
if (c == '"')
|
||||
{
|
||||
i = AppendUntilStringEnd(true, i, json);
|
||||
continue;
|
||||
}
|
||||
if (char.IsWhiteSpace(c))
|
||||
continue;
|
||||
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
|
||||
//Parse the thing!
|
||||
return (T)ParseValue(typeof(T), stringBuilder.ToString());
|
||||
}
|
||||
|
||||
static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
|
||||
{
|
||||
stringBuilder.Append(json[startIdx]);
|
||||
for (int i = startIdx + 1; i < json.Length; i++)
|
||||
{
|
||||
if (json[i] == '\\')
|
||||
{
|
||||
if (appendEscapeCharacter)
|
||||
stringBuilder.Append(json[i]);
|
||||
stringBuilder.Append(json[i + 1]);
|
||||
i++;//Skip next character as it is escaped
|
||||
}
|
||||
else if (json[i] == '"')
|
||||
{
|
||||
stringBuilder.Append(json[i]);
|
||||
return i;
|
||||
}
|
||||
else
|
||||
stringBuilder.Append(json[i]);
|
||||
}
|
||||
return json.Length - 1;
|
||||
}
|
||||
|
||||
//Splits { <value>:<value>, <value>:<value> } and [ <value>, <value> ] into a list of <value> strings
|
||||
static List<string> Split(string json)
|
||||
{
|
||||
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List<string>();
|
||||
splitArray.Clear();
|
||||
if (json.Length == 2)
|
||||
return splitArray;
|
||||
int parseDepth = 0;
|
||||
stringBuilder.Length = 0;
|
||||
for (int i = 1; i < json.Length - 1; i++)
|
||||
{
|
||||
switch (json[i])
|
||||
{
|
||||
case '[':
|
||||
case '{':
|
||||
parseDepth++;
|
||||
break;
|
||||
case ']':
|
||||
case '}':
|
||||
parseDepth--;
|
||||
break;
|
||||
case '"':
|
||||
i = AppendUntilStringEnd(true, i, json);
|
||||
continue;
|
||||
case ',':
|
||||
case ':':
|
||||
if (parseDepth == 0)
|
||||
{
|
||||
splitArray.Add(stringBuilder.ToString());
|
||||
stringBuilder.Length = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stringBuilder.Append(json[i]);
|
||||
}
|
||||
|
||||
splitArray.Add(stringBuilder.ToString());
|
||||
|
||||
return splitArray;
|
||||
}
|
||||
|
||||
internal static object ParseValue(Type type, string json)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
if (json.Length <= 2)
|
||||
return string.Empty;
|
||||
StringBuilder parseStringBuilder = new StringBuilder(json.Length);
|
||||
for (int i = 1; i < json.Length - 1; ++i)
|
||||
{
|
||||
if (json[i] == '\\' && i + 1 < json.Length - 1)
|
||||
{
|
||||
int j = "\"\\nrtbf/".IndexOf(json[i + 1]);
|
||||
if (j >= 0)
|
||||
{
|
||||
parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (json[i + 1] == 'u' && i + 5 < json.Length - 1)
|
||||
{
|
||||
//UInt32 c = 0;
|
||||
if (UInt32.TryParse(json.Substring(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out UInt32 c))
|
||||
{
|
||||
parseStringBuilder.Append((char)c);
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
parseStringBuilder.Append(json[i]);
|
||||
}
|
||||
return parseStringBuilder.ToString();
|
||||
}
|
||||
if (type.IsPrimitive)
|
||||
{
|
||||
var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture);
|
||||
return result;
|
||||
}
|
||||
if (type == typeof(decimal))
|
||||
{
|
||||
decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out decimal result);
|
||||
return result;
|
||||
}
|
||||
if (type == typeof(DateTime))
|
||||
{
|
||||
DateTime.TryParse(json.Replace("\"", ""), System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out DateTime result);
|
||||
return result;
|
||||
}
|
||||
if (json == "null")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (type.IsEnum)
|
||||
{
|
||||
if (json[0] == '"')
|
||||
json = json.Substring(1, json.Length - 2);
|
||||
try
|
||||
{
|
||||
return Enum.Parse(type, json, false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (type.IsArray)
|
||||
{
|
||||
Type arrayType = type.GetElementType();
|
||||
if (json[0] != '[' || json[json.Length - 1] != ']')
|
||||
return null;
|
||||
|
||||
List<string> elems = Split(json);
|
||||
Array newArray = Array.CreateInstance(arrayType, elems.Count);
|
||||
for (int i = 0; i < elems.Count; i++)
|
||||
newArray.SetValue(ParseValue(arrayType, elems[i]), i);
|
||||
splitArrayPool.Push(elems);
|
||||
return newArray;
|
||||
}
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
|
||||
{
|
||||
Type listType = type.GetGenericArguments()[0];
|
||||
if (json[0] != '[' || json[json.Length - 1] != ']')
|
||||
return null;
|
||||
|
||||
List<string> elems = Split(json);
|
||||
var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count });
|
||||
for (int i = 0; i < elems.Count; i++)
|
||||
list.Add(ParseValue(listType, elems[i]));
|
||||
splitArrayPool.Push(elems);
|
||||
return list;
|
||||
}
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
{
|
||||
Type keyType, valueType;
|
||||
{
|
||||
Type[] args = type.GetGenericArguments();
|
||||
keyType = args[0];
|
||||
valueType = args[1];
|
||||
}
|
||||
|
||||
//Refuse to parse dictionary keys that aren't of type string
|
||||
if (keyType != typeof(string))
|
||||
return null;
|
||||
//Must be a valid dictionary element
|
||||
if (json[0] != '{' || json[json.Length - 1] != '}')
|
||||
return null;
|
||||
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
|
||||
List<string> elems = Split(json);
|
||||
if (elems.Count % 2 != 0)
|
||||
return null;
|
||||
|
||||
var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 });
|
||||
for (int i = 0; i < elems.Count; i += 2)
|
||||
{
|
||||
if (elems[i].Length <= 2)
|
||||
continue;
|
||||
string keyValue = elems[i].Substring(1, elems[i].Length - 2);
|
||||
object val = ParseValue(valueType, elems[i + 1]);
|
||||
dictionary[keyValue] = val;
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
if (type == typeof(object))
|
||||
{
|
||||
return ParseAnonymousValue(json);
|
||||
}
|
||||
if (json[0] == '{' && json[json.Length - 1] == '}')
|
||||
{
|
||||
return ParseObject(type, json);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static object ParseAnonymousValue(string json)
|
||||
{
|
||||
if (json.Length == 0)
|
||||
return null;
|
||||
if (json[0] == '{' && json[json.Length - 1] == '}')
|
||||
{
|
||||
List<string> elems = Split(json);
|
||||
if (elems.Count % 2 != 0)
|
||||
return null;
|
||||
var dict = new Dictionary<string, object>(elems.Count / 2);
|
||||
for (int i = 0; i < elems.Count; i += 2)
|
||||
dict[elems[i].Substring(1, elems[i].Length - 2)] = ParseAnonymousValue(elems[i + 1]);
|
||||
return dict;
|
||||
}
|
||||
if (json[0] == '[' && json[json.Length - 1] == ']')
|
||||
{
|
||||
List<string> items = Split(json);
|
||||
var finalList = new List<object>(items.Count);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
finalList.Add(ParseAnonymousValue(items[i]));
|
||||
return finalList;
|
||||
}
|
||||
if (json[0] == '"' && json[json.Length - 1] == '"')
|
||||
{
|
||||
string str = json.Substring(1, json.Length - 2);
|
||||
return str.Replace("\\", string.Empty);
|
||||
}
|
||||
if (char.IsDigit(json[0]) || json[0] == '-')
|
||||
{
|
||||
if (json.Contains("."))
|
||||
{
|
||||
double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double result);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
int.TryParse(json, out int result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (json == "true")
|
||||
return true;
|
||||
if (json == "false")
|
||||
return false;
|
||||
// handles json == "null" as well as invalid JSON
|
||||
return null;
|
||||
}
|
||||
|
||||
static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members) where T : MemberInfo
|
||||
{
|
||||
Dictionary<string, T> nameToMember = new Dictionary<string, T>(StringComparer.OrdinalIgnoreCase);
|
||||
for (int i = 0; i < members.Length; i++)
|
||||
{
|
||||
T member = members[i];
|
||||
if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true))
|
||||
continue;
|
||||
|
||||
string name = member.Name;
|
||||
if (member.IsDefined(typeof(DataMemberAttribute), true))
|
||||
{
|
||||
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true);
|
||||
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
|
||||
name = dataMemberAttribute.Name;
|
||||
}
|
||||
|
||||
nameToMember.Add(name, member);
|
||||
}
|
||||
|
||||
return nameToMember;
|
||||
}
|
||||
|
||||
static object ParseObject(Type type, string json)
|
||||
{
|
||||
object instance = FormatterServices.GetUninitializedObject(type);
|
||||
|
||||
//The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
|
||||
List<string> elems = Split(json);
|
||||
if (elems.Count % 2 != 0)
|
||||
return instance;
|
||||
|
||||
//Dictionary<string, FieldInfo> nameToField;
|
||||
//Dictionary<string, PropertyInfo> nameToProperty;
|
||||
if (!fieldInfoCache.TryGetValue(type, out var nameToField))
|
||||
{
|
||||
nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
|
||||
fieldInfoCache.Add(type, nameToField);
|
||||
}
|
||||
if (!propertyInfoCache.TryGetValue(type, out var nameToProperty))
|
||||
{
|
||||
nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
|
||||
propertyInfoCache.Add(type, nameToProperty);
|
||||
}
|
||||
|
||||
for (int i = 0; i < elems.Count; i += 2)
|
||||
{
|
||||
if (elems[i].Length <= 2)
|
||||
continue;
|
||||
string key = elems[i].Substring(1, elems[i].Length - 2);
|
||||
string value = elems[i + 1];
|
||||
|
||||
if (nameToField.TryGetValue(key, out FieldInfo fieldInfo))
|
||||
fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value));
|
||||
else if (nameToProperty.TryGetValue(key, out PropertyInfo propertyInfo))
|
||||
propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Plugins/CodeAssist/Editor/TinyJson/JsonParser.cs.meta
Normal file
11
Assets/Plugins/CodeAssist/Editor/TinyJson/JsonParser.cs.meta
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c8d46955f81c1d4e9ab1586f1b9eb1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
202
Assets/Plugins/CodeAssist/Editor/TinyJson/JsonWriter.cs
Normal file
202
Assets/Plugins/CodeAssist/Editor/TinyJson/JsonWriter.cs
Normal file
|
@ -0,0 +1,202 @@
|
|||
// copied from
|
||||
// https://github.com/zanders3/json/blob/master/src/JSONWriter.cs
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
//namespace TinyJson
|
||||
namespace Meryel.UnityCodeAssist.Editor.TinyJson
|
||||
{
|
||||
//Really simple JSON writer
|
||||
//- Outputs JSON structures from an object
|
||||
//- Really simple API (new List<int> { 1, 2, 3 }).ToJson() == "[1,2,3]"
|
||||
//- Will only output public fields and property getters on objects
|
||||
//public static class JSONWriter
|
||||
public static class JsonWriter
|
||||
{
|
||||
//public static string ToJson(this object item)
|
||||
public static string ToJson(object item)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
AppendValue(stringBuilder, item);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
static void AppendValue(StringBuilder stringBuilder, object item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
stringBuilder.Append("null");
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = item.GetType();
|
||||
if (type == typeof(string) || type == typeof(char))
|
||||
{
|
||||
stringBuilder.Append('"');
|
||||
string str = item.ToString();
|
||||
for (int i = 0; i < str.Length; ++i)
|
||||
if (str[i] < ' ' || str[i] == '"' || str[i] == '\\')
|
||||
{
|
||||
stringBuilder.Append('\\');
|
||||
int j = "\"\\\n\r\t\b\f".IndexOf(str[i]);
|
||||
if (j >= 0)
|
||||
stringBuilder.Append("\"\\nrtbf"[j]);
|
||||
else
|
||||
stringBuilder.AppendFormat("u{0:X4}", (UInt32)str[i]);
|
||||
}
|
||||
else
|
||||
stringBuilder.Append(str[i]);
|
||||
stringBuilder.Append('"');
|
||||
}
|
||||
else if (type == typeof(byte) || type == typeof(sbyte))
|
||||
{
|
||||
stringBuilder.Append(item.ToString());
|
||||
}
|
||||
else if (type == typeof(short) || type == typeof(ushort))
|
||||
{
|
||||
stringBuilder.Append(item.ToString());
|
||||
}
|
||||
else if (type == typeof(int) || type == typeof(uint))
|
||||
{
|
||||
stringBuilder.Append(item.ToString());
|
||||
}
|
||||
else if (type == typeof(long) || type == typeof(ulong))
|
||||
{
|
||||
stringBuilder.Append(item.ToString());
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
stringBuilder.Append(((float)item).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
stringBuilder.Append(((double)item).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (type == typeof(decimal))
|
||||
{
|
||||
stringBuilder.Append(((decimal)item).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
stringBuilder.Append(((bool)item) ? "true" : "false");
|
||||
}
|
||||
else if (type == typeof(DateTime))
|
||||
{
|
||||
stringBuilder.Append('"');
|
||||
stringBuilder.Append(((DateTime)item).ToString(System.Globalization.CultureInfo.InvariantCulture));
|
||||
stringBuilder.Append('"');
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
stringBuilder.Append('"');
|
||||
stringBuilder.Append(item.ToString());
|
||||
stringBuilder.Append('"');
|
||||
}
|
||||
else if (item is IList)
|
||||
{
|
||||
stringBuilder.Append('[');
|
||||
bool isFirst = true;
|
||||
IList list = item as IList;
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
stringBuilder.Append(',');
|
||||
AppendValue(stringBuilder, list[i]);
|
||||
}
|
||||
stringBuilder.Append(']');
|
||||
}
|
||||
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
|
||||
{
|
||||
Type keyType = type.GetGenericArguments()[0];
|
||||
|
||||
//Refuse to output dictionary keys that aren't of type string
|
||||
if (keyType != typeof(string))
|
||||
{
|
||||
stringBuilder.Append("{}");
|
||||
return;
|
||||
}
|
||||
|
||||
stringBuilder.Append('{');
|
||||
IDictionary dict = item as IDictionary;
|
||||
bool isFirst = true;
|
||||
foreach (object key in dict.Keys)
|
||||
{
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
stringBuilder.Append(',');
|
||||
stringBuilder.Append('\"');
|
||||
stringBuilder.Append((string)key);
|
||||
stringBuilder.Append("\":");
|
||||
AppendValue(stringBuilder, dict[key]);
|
||||
}
|
||||
stringBuilder.Append('}');
|
||||
}
|
||||
else
|
||||
{
|
||||
stringBuilder.Append('{');
|
||||
|
||||
bool isFirst = true;
|
||||
FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
|
||||
for (int i = 0; i < fieldInfos.Length; i++)
|
||||
{
|
||||
if (fieldInfos[i].IsDefined(typeof(IgnoreDataMemberAttribute), true))
|
||||
continue;
|
||||
|
||||
object value = fieldInfos[i].GetValue(item);
|
||||
if (value != null)
|
||||
{
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
stringBuilder.Append(',');
|
||||
stringBuilder.Append('\"');
|
||||
stringBuilder.Append(GetMemberName(fieldInfos[i]));
|
||||
stringBuilder.Append("\":");
|
||||
AppendValue(stringBuilder, value);
|
||||
}
|
||||
}
|
||||
PropertyInfo[] propertyInfo = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
|
||||
for (int i = 0; i < propertyInfo.Length; i++)
|
||||
{
|
||||
if (!propertyInfo[i].CanRead || propertyInfo[i].IsDefined(typeof(IgnoreDataMemberAttribute), true))
|
||||
continue;
|
||||
|
||||
object value = propertyInfo[i].GetValue(item, null);
|
||||
if (value != null)
|
||||
{
|
||||
if (isFirst)
|
||||
isFirst = false;
|
||||
else
|
||||
stringBuilder.Append(',');
|
||||
stringBuilder.Append('\"');
|
||||
stringBuilder.Append(GetMemberName(propertyInfo[i]));
|
||||
stringBuilder.Append("\":");
|
||||
AppendValue(stringBuilder, value);
|
||||
}
|
||||
}
|
||||
|
||||
stringBuilder.Append('}');
|
||||
}
|
||||
}
|
||||
|
||||
static string GetMemberName(MemberInfo member)
|
||||
{
|
||||
if (member.IsDefined(typeof(DataMemberAttribute), true))
|
||||
{
|
||||
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true);
|
||||
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
|
||||
return dataMemberAttribute.Name;
|
||||
}
|
||||
|
||||
return member.Name;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue