mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-11-11 08:38:45 +00:00
提交Unity 联机Pro
This commit is contained in:
44
JNFrame2/Assets/Plugins/SRDebugger/Scripts/AutoInitialize.cs
Normal file
44
JNFrame2/Assets/Plugins/SRDebugger/Scripts/AutoInitialize.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using SRDebugger.Services;
|
||||
using SRF.Service;
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
public static class AutoInitialize
|
||||
{
|
||||
#if UNITY_2018
|
||||
private const RuntimeInitializeLoadType InitializeLoadType = RuntimeInitializeLoadType.BeforeSceneLoad;
|
||||
#else
|
||||
private const RuntimeInitializeLoadType InitializeLoadType = RuntimeInitializeLoadType.SubsystemRegistration;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the console service before the scene has loaded to catch more of the initialization log.
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(InitializeLoadType)]
|
||||
public static void OnLoadBeforeScene()
|
||||
{
|
||||
// Populate service manager with types from SRDebugger assembly (asmdef)
|
||||
SRServiceManager.RegisterAssembly<IDebugService>();
|
||||
|
||||
if (Settings.Instance.IsEnabled)
|
||||
{
|
||||
// Initialize console if it hasn't already initialized.
|
||||
SRServiceManager.GetService<IConsoleService>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize SRDebugger after the scene has loaded.
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
public static void OnLoad()
|
||||
{
|
||||
if (Settings.Instance.IsEnabled)
|
||||
{
|
||||
SRDebug.Init();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7261eeb6c603844ba967b14c0895ec8
|
||||
timeCreated: 1426170121
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor.meta
Normal file
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b75fb5ec74e4fa4ca7d8472defae919
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
101
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor/ApiSignup.cs
Normal file
101
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor/ApiSignup.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Cache;
|
||||
using System.Text;
|
||||
using SRF;
|
||||
using UnityEngine;
|
||||
using SRDebugger.Internal;
|
||||
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
static class ApiSignup
|
||||
{
|
||||
public delegate void ApiSignupResultCallback(bool success, string apiKey, string email, string error);
|
||||
|
||||
public static void SignUp(string email, string invoiceNo, ApiSignupResultCallback resultCallback)
|
||||
{
|
||||
var requestData = new Hashtable();
|
||||
requestData["emailAddress"] = email;
|
||||
requestData["transactionNumber"] = invoiceNo;
|
||||
|
||||
try
|
||||
{
|
||||
var request = SendRequest(SRDebugApi.EndPoint + "/user/create", requestData, WebRequestMethods.Http.Post);
|
||||
|
||||
string result;
|
||||
|
||||
var didSucceed = SRDebugApiUtil.ReadResponse(request, out result);
|
||||
|
||||
if (didSucceed)
|
||||
{
|
||||
var jsonTable = (Dictionary<string, object>) Json.Deserialize(result);
|
||||
|
||||
resultCallback(true, (string) jsonTable["apiKey"], (string) jsonTable["emailAddress"], null);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultCallback(false, null, null, SRDebugApiUtil.ParseErrorResponse(result));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
resultCallback(false, null, null, "Internal Error (" + e.Message + ")");
|
||||
}
|
||||
}
|
||||
|
||||
public static string Verify(string apiKey)
|
||||
{
|
||||
var request = SendRequest(SRDebugApi.EndPoint + "/user/test", null, apiKey: apiKey);
|
||||
|
||||
string result;
|
||||
|
||||
SRDebugApiUtil.ReadResponse(request, out result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static HttpWebRequest SendRequest(string endpoint, Hashtable data,
|
||||
string method = WebRequestMethods.Http.Get, string apiKey = null)
|
||||
{
|
||||
var request = (HttpWebRequest) WebRequest.Create(endpoint);
|
||||
request.Timeout = 15000;
|
||||
request.Method = method;
|
||||
|
||||
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.BypassCache);
|
||||
|
||||
request.ContentType = "application/json";
|
||||
request.Accept = "application/json";
|
||||
|
||||
if (!string.IsNullOrEmpty(apiKey))
|
||||
{
|
||||
request.Headers.Add("X-ApiKey", apiKey);
|
||||
}
|
||||
|
||||
request.KeepAlive = false;
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
var requestJson = Json.Serialize(data);
|
||||
|
||||
using (var requestStream = request.GetRequestStream())
|
||||
{
|
||||
using (var writer = new StreamWriter(requestStream, Encoding.UTF8))
|
||||
{
|
||||
writer.Write(requestJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c678ba20e05678942905f13f1f42c8e1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
class ApiSignupTermsWindow : EditorWindow
|
||||
{
|
||||
public static void Open()
|
||||
{
|
||||
GetWindowWithRect<ApiSignupTermsWindow>(new Rect(0, 0, 430, 345), true, "SRDebugger - Bug Reporter TOS",
|
||||
true);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.Label("Terms and Conditions", SRInternalEditorUtil.Styles.HeaderLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"The Bug Reporter service is provided free of charge to owners of SRDebugger. One valid license key of SRDebugger allows one account to be registered. You must not share your API key with another party. Stompy Robot LTD reserves the right to terminate your bug reporter account if your API key is shared with another party.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"Stompy Robot LTD reserves the right to cancel the bug report service at any time without notice.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"By signing up for the Bug Reporter service you grant Stompy Robot LTD permission to gather non-identifying information from users when submitting reports. You attest that your users are aware of the data collection and give their consent.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"THE SERVICE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("Close"))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58b4c2d8acab3b747a2a90abd77b1132
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
abstract class IntegrityIssue
|
||||
{
|
||||
private readonly string _title;
|
||||
private readonly string _description;
|
||||
private List<Fix> _fixes;
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return _title; }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
}
|
||||
|
||||
public IList<Fix> GetFixes()
|
||||
{
|
||||
if (_fixes == null)
|
||||
{
|
||||
_fixes = CreateFixes().ToList();
|
||||
}
|
||||
|
||||
return _fixes;
|
||||
}
|
||||
|
||||
protected IntegrityIssue(string title, string description)
|
||||
{
|
||||
_title = title;
|
||||
_description = description;
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<Fix> CreateFixes();
|
||||
}
|
||||
|
||||
abstract class Fix
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly string _description;
|
||||
private readonly bool _isAutoFix;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
}
|
||||
|
||||
public bool IsAutoFix
|
||||
{
|
||||
get { return _isAutoFix; }
|
||||
}
|
||||
|
||||
protected Fix(string name, string description, bool isAutoFix)
|
||||
{
|
||||
_name = name;
|
||||
_description = description;
|
||||
_isAutoFix = isAutoFix;
|
||||
}
|
||||
|
||||
public abstract void Execute();
|
||||
}
|
||||
|
||||
class DelegateFix : Fix
|
||||
{
|
||||
private readonly Action _fixMethod;
|
||||
|
||||
public DelegateFix(string name, string description, Action fixMethod) : base(name, description, true)
|
||||
{
|
||||
_fixMethod = fixMethod;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
_fixMethod();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fab9c606533743f6bfcb59f8392b1a0c
|
||||
timeCreated: 1611921984
|
||||
123
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor/Migrations.cs
Normal file
123
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor/Migrations.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SRF;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
#pragma warning disable 162
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
static class Migrations
|
||||
{
|
||||
static Migrations()
|
||||
{
|
||||
RunMigrations();
|
||||
}
|
||||
|
||||
private const bool EnableLog = false;
|
||||
|
||||
public class Migration
|
||||
{
|
||||
public readonly string Id;
|
||||
public readonly string[] ObsoleteFiles;
|
||||
|
||||
public Migration(string id, string[] obsoleteFiles)
|
||||
{
|
||||
Id = id;
|
||||
ObsoleteFiles = obsoleteFiles;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Migration> AvailableMigrations = new List<Migration>()
|
||||
{
|
||||
new Migration("DeleteOldEditorResources", new[]
|
||||
{
|
||||
"Editor/Resources/SRDebugger/BG_Dark.png",
|
||||
"Editor/Resources/SRDebugger/BG_Light.png",
|
||||
"Editor/Resources/SRDebugger/DemoSprite.png",
|
||||
"Editor/Resources/SRDebugger/Logo_DarkBG.png",
|
||||
"Editor/Resources/SRDebugger/Logo_LightBG.png",
|
||||
"Editor/Resources/SRDebugger/WelcomeLogo_DarkBG.png",
|
||||
"Editor/Resources/SRDebugger/WelcomeLogo_LightBG.png",
|
||||
"Editor/Resources/SRDebugger/Icons/Dark/console-25.png",
|
||||
"Editor/Resources/SRDebugger/Icons/Dark/options-25.png",
|
||||
"Editor/Resources/SRDebugger/Icons/Dark/profiler-25.png",
|
||||
"Editor/Resources/SRDebugger/Icons/Light/console-25.png",
|
||||
"Editor/Resources/SRDebugger/Icons/Light/options-25.png",
|
||||
"Editor/Resources/SRDebugger/Icons/Light/profiler-25.png",
|
||||
})
|
||||
};
|
||||
|
||||
public static void RunMigrations(bool forceRun = false)
|
||||
{
|
||||
if(EnableLog)
|
||||
Debug.Log("[SRDebugger] Running Migrations...");
|
||||
|
||||
foreach (var m in AvailableMigrations)
|
||||
{
|
||||
var key = GetProjectPrefsKey(m.Id);
|
||||
|
||||
if (!forceRun && EditorPrefs.GetBool(key, false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EditorPrefs.SetBool(key, true);
|
||||
RunMigration(m);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunMigration(Migration migration)
|
||||
{
|
||||
if (EnableLog)
|
||||
Debug.Log("Running Migration: " + migration.Id);
|
||||
|
||||
var assetPaths = AssetDatabase.GetAllAssetPaths();
|
||||
var root = new DirectoryInfo(SRInternalEditorUtil.GetRootPath());
|
||||
|
||||
if(EnableLog)
|
||||
Debug.Log("Using Root Path: " + root.FullName);
|
||||
|
||||
var obsoleteAssets = migration.ObsoleteFiles.Select(p => root + "/" + p).ToList();
|
||||
var deleteQueue = assetPaths.Where(assetPath => obsoleteAssets.Contains(assetPath)).ToList();
|
||||
|
||||
if (deleteQueue.Count == 0)
|
||||
return;
|
||||
|
||||
var message = "The following files used by a previous version of SRDebugger are obsolete and can be safely deleted: \n\n" +
|
||||
deleteQueue.Aggregate((s1, s2) => s1 + "\n" + s2);
|
||||
|
||||
Debug.Log(message);
|
||||
|
||||
message += "\n\nIt is recommended to delete these files.";
|
||||
|
||||
if (EditorUtility.DisplayDialog("SRDebugger Migration Assistant",
|
||||
message, "Delete Now", "Ignore"))
|
||||
{
|
||||
foreach (var s in deleteQueue)
|
||||
{
|
||||
Debug.Log("[SRDebugger] Deleting Asset {0}".Fmt(s));
|
||||
|
||||
if (!AssetDatabase.DeleteAsset(s))
|
||||
{
|
||||
Debug.LogWarning("[SRDebugger] Error deleting asset {0}".Fmt(s));
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("[SRDebugger] Migration Complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("SRDebugger Migration Assitant",
|
||||
"You can run this migration check again via the \"Run Migrations\" button in the advanced tab of the SRDebugger settings window.", "OK");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetProjectPrefsKey(string key)
|
||||
{
|
||||
return "SRDebugger_Migration_" + Application.dataPath + "_" + key;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b80f539792faff4187cbd7fb1113d67
|
||||
timeCreated: 1451840376
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
* This file has been deleted.
|
||||
* This empty file is left here to ensure it is properly overwritten when importing a new version of the package over an old version.
|
||||
*/
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c38092124e5b1114d9f037f64769dc5f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
public partial class SRDebugEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets compiler define <paramref name="define"/> to be enabled/disabled on all build targets.
|
||||
/// </summary>
|
||||
static void SetCompileDefine(string define, bool enabled)
|
||||
{
|
||||
foreach (BuildTargetGroup targetGroup in GetAllBuildTargetGroups())
|
||||
{
|
||||
// Use hash set to remove duplicates.
|
||||
List<string> defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup).Split(';').ToList();
|
||||
|
||||
bool alreadyExists = false;
|
||||
|
||||
for (var i = 0; i < defines.Count; i++)
|
||||
{
|
||||
if (string.Equals(define, defines[i], StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
alreadyExists = true;
|
||||
if (!enabled)
|
||||
{
|
||||
defines.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyExists && enabled)
|
||||
{
|
||||
defines.Add(define);
|
||||
}
|
||||
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, string.Join(";", defines.ToArray()));
|
||||
}
|
||||
}
|
||||
static void ForceRecompile()
|
||||
{
|
||||
AssetDatabase.ImportAsset(SRInternalEditorUtil.GetAssetPath("StompyRobot.SRDebugger.asmdef"), ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
static IEnumerable<BuildTargetGroup> GetAllBuildTargetGroups()
|
||||
{
|
||||
Type enumType = typeof(BuildTargetGroup);
|
||||
string[] names = Enum.GetNames(enumType);
|
||||
Array values = Enum.GetValues(enumType);
|
||||
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
{
|
||||
string name = names[i];
|
||||
BuildTargetGroup value = (BuildTargetGroup)values.GetValue(i);
|
||||
|
||||
if (value == BuildTargetGroup.Unknown) continue;
|
||||
|
||||
MemberInfo[] member = enumType.GetMember(name);
|
||||
MemberInfo entry = member.FirstOrDefault(p => p.DeclaringType == enumType);
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
Debug.LogErrorFormat(
|
||||
"[SRDebugger] Unhandled build target: {0}. SRDebugger disabled state may not be applied correctly to this platform.",
|
||||
name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length != 0)
|
||||
{
|
||||
// obsolete, ignore.
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9adb2a4b8a61fe47ba3c6717de5f78b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
public partial class SRDebugEditor
|
||||
{
|
||||
internal const string DisabledDirectoryPostfix = "_DISABLED~";
|
||||
|
||||
// Paths to enable/disable (relative to SRDebugger root directory)
|
||||
private static readonly string[] _resourcePaths = new[]
|
||||
{
|
||||
"Resources",
|
||||
"usr",
|
||||
"UI/Prefabs"
|
||||
};
|
||||
|
||||
static void SetResourcesEnabled(bool enable)
|
||||
{
|
||||
AssetDatabase.StartAssetEditing();
|
||||
|
||||
foreach (ResourceDirectory d in GetResourcePaths())
|
||||
{
|
||||
d.SetDirectoryEnabled(enable);
|
||||
}
|
||||
|
||||
AssetDatabase.StopAssetEditing();
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
AssetDatabase.ImportAsset(SRInternalEditorUtil.GetRootPath(
|
||||
), ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
internal static IEnumerable<ResourceDirectory> GetResourcePaths()
|
||||
{
|
||||
foreach (string resourcePath in _resourcePaths)
|
||||
{
|
||||
string enabledPath = Path.Combine(SRInternalEditorUtil.GetRootPath(), resourcePath);
|
||||
string disabledPath = Path.Combine(SRInternalEditorUtil.GetRootPath(), resourcePath) + DisabledDirectoryPostfix;
|
||||
|
||||
yield return new ResourceDirectory(enabledPath, disabledPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class ResourceDirectory
|
||||
{
|
||||
public readonly string EnabledPath;
|
||||
public readonly string DisabledPath;
|
||||
|
||||
public readonly string EnabledPathMetaFile;
|
||||
public readonly string DisabledPathMetaFile;
|
||||
public readonly string DisabledPathBackupMetaFile;
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get { return Directory.Exists(EnabledPath); }
|
||||
}
|
||||
|
||||
public bool IsDisabled
|
||||
{
|
||||
get { return Directory.Exists(DisabledPath); }
|
||||
}
|
||||
|
||||
public ResourceDirectory(string enabledPath, string disabledPath)
|
||||
{
|
||||
EnabledPath = enabledPath;
|
||||
DisabledPath = disabledPath;
|
||||
|
||||
EnabledPathMetaFile = enabledPath + ".meta";
|
||||
DisabledPathMetaFile = disabledPath + ".meta";
|
||||
DisabledPathBackupMetaFile = disabledPath + ".meta.bak~";
|
||||
}
|
||||
|
||||
public void SetDirectoryEnabled(bool enable)
|
||||
{
|
||||
if (IsEnabled && enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDisabled && !enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsEnabled && IsDisabled)
|
||||
{
|
||||
// TODO
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
string title = string.Format("SRDebugger - {0} Resources", enable ? "Enable" : "Disable");
|
||||
|
||||
string oldPath = enable ? DisabledPath : EnabledPath;
|
||||
string newPath = enable ? EnabledPath : DisabledPath;
|
||||
bool useAssetDatabase = !enable;
|
||||
|
||||
string error = null;
|
||||
|
||||
if (useAssetDatabase)
|
||||
{
|
||||
error = AssetDatabase.MoveAsset(oldPath, newPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog(title, GetErrorMessage(enable, error), "Force Move", "Abort"))
|
||||
{
|
||||
useAssetDatabase = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!useAssetDatabase)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Move(oldPath, newPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("Error moving directory");
|
||||
Debug.LogException(e);
|
||||
error = "Exception occurred, see console for details.";
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
{
|
||||
string message = string.Format(
|
||||
"An error occurred while attempting to {3} SRDebugger resource directory.\n\n Old Path: {0}\n New Path: {1}\n\n Error: \n{2}",
|
||||
EnabledPath, DisabledPath, error, enable ? "enable" : "disable");
|
||||
|
||||
EditorUtility.DisplayDialog(title, message, "Continue");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enable)
|
||||
{
|
||||
// Disable meta files
|
||||
if (File.Exists(DisabledPathMetaFile))
|
||||
{
|
||||
if (File.Exists(DisabledPathBackupMetaFile))
|
||||
{
|
||||
File.Delete(DisabledPathBackupMetaFile);
|
||||
}
|
||||
|
||||
File.Move(DisabledPathMetaFile, DisabledPathBackupMetaFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable backed up meta files
|
||||
if (File.Exists(DisabledPathBackupMetaFile))
|
||||
{
|
||||
if (File.Exists(EnabledPathMetaFile))
|
||||
{
|
||||
File.Delete(EnabledPathMetaFile);
|
||||
}
|
||||
|
||||
File.Move(DisabledPathBackupMetaFile, EnabledPathMetaFile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetErrorMessage(bool enable, string error)
|
||||
{
|
||||
return string.Format(
|
||||
"An error occurred while attempting to {3} SRDebugger resources. \n\n Old Path: {0}\n New Path: {1}\n\n Error: \n{2}",
|
||||
EnabledPath, DisabledPath, error, enable ? "enable" : "disable");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d6ba6f98fe1a9c4e8c082aa4aed6922
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,308 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
public static partial class SRDebugEditor
|
||||
{
|
||||
internal const string DisableSRDebuggerCompileDefine = "DISABLE_SRDEBUGGER";
|
||||
|
||||
/// <summary>
|
||||
/// Is SRDebugger currently enabled or disabled.
|
||||
/// </summary>
|
||||
public static readonly bool IsEnabled =
|
||||
#if DISABLE_SRDEBUGGER
|
||||
false
|
||||
#else
|
||||
true
|
||||
#endif
|
||||
;
|
||||
|
||||
/// <summary>
|
||||
/// Set SRDebugger to be enabled or disabled.
|
||||
/// This is a synchronous operation, which means calling this as part of a build pipeline should be possible.
|
||||
/// </summary>
|
||||
/// <param name="enable"></param>
|
||||
public static void SetEnabled(bool enable)
|
||||
{
|
||||
if (EditorApplication.isPlaying || EditorApplication.isCompiling)
|
||||
{
|
||||
Debug.LogError(
|
||||
"[SRDebugger.SetEnabled] Can't change SRDebugger enabled state while in play mode or compiling scripts.");
|
||||
throw new InvalidOperationException(
|
||||
"Can't change SRDebugger enabled state while in play mode or compiling scripts.");
|
||||
}
|
||||
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
AssetDatabase.SaveAssets(); // In case any pending changes to files about to be moved
|
||||
|
||||
// Try and unload the settings asset to prevent errors later (harmless error, but annoying)
|
||||
SRInternalEditorUtil.EditorSettings.ClearCache();
|
||||
GC.Collect();
|
||||
EditorUtility.UnloadUnusedAssetsImmediate(true);
|
||||
#endif
|
||||
|
||||
AssetDatabase.ReleaseCachedFileHandles();
|
||||
|
||||
SetCompileDefine(DisableSRDebuggerCompileDefine, !enable);
|
||||
SetResourcesEnabled(enable);
|
||||
|
||||
ForceRecompile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs through a series of integrity checks that are fast to perform.
|
||||
/// </summary>
|
||||
internal static IEnumerable<IntegrityIssue> QuickIntegrityCheck()
|
||||
{
|
||||
int enabledCount = 0;
|
||||
int disabledCount = 0;
|
||||
|
||||
foreach (ResourceDirectory directory in GetResourcePaths())
|
||||
{
|
||||
if (directory.IsEnabled && directory.IsDisabled)
|
||||
{
|
||||
yield return new SomeResourcesAreEnabledAndDisabledIntegrityIssue();
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (directory.IsEnabled) enabledCount++;
|
||||
if (directory.IsDisabled) disabledCount++;
|
||||
}
|
||||
|
||||
if (enabledCount > 0 && disabledCount > 0)
|
||||
{
|
||||
#if DISABLE_SRDEBUGGER
|
||||
yield return new SomeResourcesEnabledIntegrityIssue();
|
||||
#else
|
||||
yield return new SomeResourcesDisabledIntegrityIssue();
|
||||
#endif
|
||||
yield break; // Don't do any further resource-related checks.
|
||||
}
|
||||
|
||||
if (!IsEnabled && enabledCount > 0)
|
||||
{
|
||||
yield return new ScriptsDisabledButResourcesEnabled();
|
||||
}
|
||||
|
||||
if (IsEnabled && disabledCount > 0)
|
||||
{
|
||||
yield return new ScriptsEnabledButResourcesDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DrawDisabledWindowGui(ref bool isWorking)
|
||||
{
|
||||
SRInternalEditorUtil.BeginDrawBackground();
|
||||
SRInternalEditorUtil.DrawLogo(SRInternalEditorUtil.GetLogo());
|
||||
SRInternalEditorUtil.EndDrawBackground();
|
||||
|
||||
// Draw header/content divider
|
||||
EditorGUILayout.BeginVertical(SRInternalEditorUtil.Styles.SettingsHeaderBoxStyle);
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
GUILayout.Label("SRDebugger Disabled", SRInternalEditorUtil.Styles.InspectorHeaderStyle);
|
||||
|
||||
GUILayout.Label(
|
||||
"SRDebugger is currently disabled. SRDebugger must be enabled in order to access editor features.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
EditorGUILayout.HelpBox("Enabling SRDebugger will result in the tools being included in all builds of your game until it is disabled again.", MessageType.Warning);
|
||||
|
||||
GUILayout.Label("• "+ DisableSRDebuggerCompileDefine + " compiler define will be removed from all build configurations.", SRInternalEditorUtil.Styles.ListBulletPoint);
|
||||
GUILayout.Label("• Disabled SRDebugger folders will be renamed so Unity imports them.", SRInternalEditorUtil.Styles.ListBulletPoint);
|
||||
GUILayout.Label("• You can disable SRDebugger again at any time.", SRInternalEditorUtil.Styles.ListBulletPoint);
|
||||
|
||||
if (isWorking && !EditorApplication.isCompiling && !EditorApplication.isUpdating)
|
||||
{
|
||||
isWorking = false;
|
||||
}
|
||||
|
||||
if (isWorking)
|
||||
{
|
||||
using (new EditorGUI.DisabledGroupScope(true))
|
||||
{
|
||||
GUILayout.Button("Working...");
|
||||
}
|
||||
}
|
||||
else if (GUILayout.Button("Enable SRDebugger"))
|
||||
{
|
||||
isWorking = true;
|
||||
try
|
||||
{
|
||||
SetEnabled(true);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
isWorking = false;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DISABLE_SRDEBUGGER
|
||||
class SomeResourcesEnabledIntegrityIssue : IntegrityIssue
|
||||
{
|
||||
private new const string Title = "Some SRDebugger resources are enabled.";
|
||||
|
||||
private new const string Description =
|
||||
"SRDebugger is disabled, but some SRDebugger resource directories are enabled. \n\n" +
|
||||
"This can occur if an unhandled error occurs while SRDebugger is being enabled or disabled, or if the resource directories are modified by hand.";
|
||||
|
||||
public SomeResourcesEnabledIntegrityIssue() : base(Title, Description)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override IEnumerable<Fix> CreateFixes()
|
||||
{
|
||||
yield return new DelegateFix(
|
||||
"Disable all SRDebugger resources",
|
||||
"All resource directories will be disabled.",
|
||||
() => { SetResourcesEnabled(false); });
|
||||
yield return new DelegateFix(
|
||||
"Enable SRDebugger",
|
||||
"Fully enable SRDebugger (activate scripts and enable resources).",
|
||||
() => { SetEnabled(true); });
|
||||
}
|
||||
}
|
||||
#else
|
||||
class SomeResourcesDisabledIntegrityIssue : IntegrityIssue
|
||||
{
|
||||
private new const string Title = "Some SRDebugger resources are disabled.";
|
||||
|
||||
private new const string Description =
|
||||
"SRDebugger is enabled, but some SRDebugger resource directories are disabled. \n\n" +
|
||||
"This can occur if an unhandled error occurs while SRDebugger is being enabled or disabled, or if the resource directories are modified by hand.";
|
||||
|
||||
public SomeResourcesDisabledIntegrityIssue() : base(Title, Description)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override IEnumerable<Fix> CreateFixes()
|
||||
{
|
||||
yield return new DelegateFix(
|
||||
"Enable all SRDebugger resources",
|
||||
"All resource directories will be enabled.",
|
||||
() => { SetResourcesEnabled(true); });
|
||||
|
||||
yield return new DelegateFix(
|
||||
"Disable SRDebugger",
|
||||
"Fully disable SRDebugger (deactivate scripts, exclude all resources from builds of your game).",
|
||||
() => { SetEnabled(false); });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class SomeResourcesAreEnabledAndDisabledIntegrityIssue : IntegrityIssue
|
||||
{
|
||||
private new const string Title = "Duplicate SRDebugger resource directories";
|
||||
|
||||
private new const string Description =
|
||||
"Some SRDebugger resource directories exist in both an enabled and disabled state. \n\n" +
|
||||
"This can occur if a new version of SRDebugger is installed while SRDebugger is disabled, or if an unhandled error occurs while SRDebugger is being enabled/disabled.";
|
||||
|
||||
public SomeResourcesAreEnabledAndDisabledIntegrityIssue() : base(Title, Description)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override IEnumerable<Fix> CreateFixes()
|
||||
{
|
||||
if (!IsEnabled)
|
||||
{
|
||||
var deletePaths = GetResourcePaths().Where(p => p.IsDisabled && p.IsEnabled).ToList();
|
||||
string paths = " - " + string.Join("\n - ", deletePaths
|
||||
.SelectMany(p => new string[] { p.DisabledPath, p.DisabledPathBackupMetaFile }).ToArray());
|
||||
|
||||
yield return new DelegateFix(
|
||||
"Keep enabled resources, disable SRDebugger",
|
||||
"If you have just installed a new version of SRDebugger, this will keep the most up-to-date resources from the imported package. SRDebugger will be disabled after the old resources are deleted. \n\n The following paths will be deleted: \n\n" + paths,
|
||||
() =>
|
||||
{
|
||||
foreach (ResourceDirectory rd in GetResourcePaths())
|
||||
{
|
||||
if (rd.IsEnabled && rd.IsDisabled)
|
||||
{
|
||||
Debug.Log("[SRDebugger] Delete Path: " + rd.DisabledPath);
|
||||
Directory.Delete(rd.DisabledPath, true);
|
||||
|
||||
Debug.Log("[SRDebugger] Delete File: " + rd.DisabledPathBackupMetaFile);
|
||||
File.Delete(rd.DisabledPathBackupMetaFile);
|
||||
}
|
||||
}
|
||||
|
||||
SetEnabled(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptsDisabledButResourcesEnabled : IntegrityIssue
|
||||
{
|
||||
private new const string Title = "SRDebugger resources are enabled while scripts are disabled";
|
||||
|
||||
private new const string Description =
|
||||
"SRDebugger's resources directories are enabled, but SRDebugger scripts are disabled. \n" +
|
||||
"This can occur if the resource directories or if the C# compile defines are modified manually.";
|
||||
|
||||
public ScriptsDisabledButResourcesEnabled() : base(Title, Description)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Fix> CreateFixes()
|
||||
{
|
||||
yield return new DelegateFix(
|
||||
"Enable SRDebugger scripts",
|
||||
"Remove compiler define (" + DisableSRDebuggerCompileDefine + ") SRDebugger can be disabled again from the settings menu.",
|
||||
() =>
|
||||
{
|
||||
SetCompileDefine(DisableSRDebuggerCompileDefine, false);
|
||||
});
|
||||
yield return new DelegateFix(
|
||||
"Disable SRDebugger resources",
|
||||
"Resources will no longer be included in builds of your game (you can enable SRDebugger from the settings menu later)",
|
||||
() =>
|
||||
{
|
||||
SetResourcesEnabled(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptsEnabledButResourcesDisabled : IntegrityIssue
|
||||
{
|
||||
private new const string Title = "SRDebugger scripts are enabled while resources are disabled.";
|
||||
|
||||
private new const string Description =
|
||||
"SRDebugger resources directories are disabled, but SRDebugger scripts are still enabled. \n" +
|
||||
"This can occur if the resource directories or C# compile defines are modified manually.";
|
||||
|
||||
public ScriptsEnabledButResourcesDisabled() : base(Title, Description)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<Fix> CreateFixes()
|
||||
{
|
||||
yield return new DelegateFix(
|
||||
"Disable SRDebugger scripts",
|
||||
"Add compiler define (" + DisableSRDebuggerCompileDefine + ") to disable SRDebugger scripts (you can re-enable SRDebugger from the settings menu later)",
|
||||
() =>
|
||||
{
|
||||
SetCompileDefine(DisableSRDebuggerCompileDefine, true);
|
||||
});
|
||||
yield return new DelegateFix(
|
||||
"Enable SRDebugger resources",
|
||||
"Resources will be included in builds of your game (you can disable SRDebugger from the settings menu later)",
|
||||
() =>
|
||||
{
|
||||
SetResourcesEnabled(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca60d3f1302b47e1a3c6f43ed06dedcf
|
||||
timeCreated: 1611413144
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
static class SRDebugEditorPaths
|
||||
{
|
||||
public const string EditorLogoPath = "UI/Sprites/Default/Logo.psd";
|
||||
|
||||
public const string SettingsMenuItemPath = "Window/SRDebugger/Settings Window";
|
||||
public const string WelcomeItemPath = "Window/SRDebugger/Welcome Guide";
|
||||
public const string SROptionsMenuItemPath = "Window/SRDebugger/SROptions Window";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6eeabd6854ed440ab38998300a297c0b
|
||||
timeCreated: 1611414784
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
class SRDebugEditorStrings
|
||||
{
|
||||
public static readonly SRDebugEditorStrings Current = new SRDebugEditorStrings();
|
||||
|
||||
public readonly string SettingsIsEnabledTooltip =
|
||||
"If false, SRDebugger.Init prefab will not load SRDebugger. Manual calls to SRDebug.Instance.ShowDebugPanel() will still work.";
|
||||
|
||||
public readonly string SettingsAutoLoadTooltip =
|
||||
"Automatically load SRDebugger when the game loads, even if SRDebugger.Init prefab is not present.";
|
||||
|
||||
public readonly string SettingsDefaultTabTooltip =
|
||||
"Visible tab when panel is first opened.";
|
||||
|
||||
public readonly string SettingsKeyboardShortcutsTooltip =
|
||||
"Enable Keyboard Shortcuts";
|
||||
|
||||
public readonly string SettingsCloseOnEscapeTooltip =
|
||||
"Close debug panel when Escape is pressed.";
|
||||
|
||||
public readonly string SettingsKeyboardModifersTooltip =
|
||||
"Modifier keys that must be held for keyboard shortcuts to execute.";
|
||||
|
||||
public readonly string SettingsDebugCameraTooltip =
|
||||
"UI will render to a camera instead of overlaying the entire scene.";
|
||||
|
||||
public readonly string SettingsRateBoxContents =
|
||||
"If you like SRDebugger, please consider leaving a rating on the Asset Store.";
|
||||
|
||||
public readonly string SettingsWebSiteUrl = "https://www.stompyrobot.uk/tools/srdebugger";
|
||||
|
||||
public readonly string SettingsAssetStoreUrl = "http://u3d.as/aZc";
|
||||
|
||||
public readonly string SettingsDocumentationUrl = "https://www.stompyrobot.uk/tools/srdebugger/documentation";
|
||||
|
||||
public readonly string SettingsSupportUrl =
|
||||
"http://forum.unity3d.com/threads/srdebugger-debug-and-tweak-your-game-while-on-device-released.296403/";
|
||||
|
||||
public readonly string SettingsEnabledTabsDescription =
|
||||
"Deselect any tabs that you do not wish to be available in the debug panel.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd05741ba3454346864f3c28fcdce56f
|
||||
timeCreated: 1611414505
|
||||
@@ -0,0 +1,183 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
class SRIntegrityCheckWindow : EditorWindow
|
||||
{
|
||||
private List<IntegrityIssue> _results;
|
||||
private Vector2 _scrollPosition;
|
||||
|
||||
private bool _applyingFix;
|
||||
private static bool _isOpen;
|
||||
|
||||
static SRIntegrityCheckWindow()
|
||||
{
|
||||
// Delay call to prevent any UI stalls after compile complete.
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (!_isOpen && SRDebugEditor.QuickIntegrityCheck().Any())
|
||||
{
|
||||
Debug.Log("[SRDebugger] Some issues have been detected with SRDebugger, opening integrity check window.");
|
||||
Open();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void Open()
|
||||
{
|
||||
var window = GetWindow<SRIntegrityCheckWindow>(true, "SRDebugger Integrity Check", true);
|
||||
window.minSize = new Vector2(640, 400);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_isOpen = true;
|
||||
RefreshIntegrityCheck();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_isOpen = false;
|
||||
}
|
||||
|
||||
public void RefreshIntegrityCheck()
|
||||
{
|
||||
_results = SRDebugEditor.QuickIntegrityCheck().ToList();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// Draw header area
|
||||
SRInternalEditorUtil.BeginDrawBackground();
|
||||
SRInternalEditorUtil.DrawLogo(SRInternalEditorUtil.GetLogo());
|
||||
SRInternalEditorUtil.EndDrawBackground();
|
||||
|
||||
// Draw header/content divider
|
||||
EditorGUILayout.BeginVertical(SRInternalEditorUtil.Styles.SettingsHeaderBoxStyle);
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
GUILayout.Label(
|
||||
"SRDebugger automatically scans your project to find common issues with the SRDebugger installation.");
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// TODO: Enable button when there are some more 'expensive' integrity checks. For now no point as alt the checks are really quick
|
||||
if (GUILayout.Button("Refresh"))
|
||||
{
|
||||
RefreshIntegrityCheck();
|
||||
}
|
||||
|
||||
if (_applyingFix)
|
||||
{
|
||||
if (!EditorApplication.isCompiling && !EditorApplication.isUpdating)
|
||||
{
|
||||
_applyingFix = false;
|
||||
RefreshIntegrityCheck();
|
||||
}
|
||||
|
||||
EditorGUI.BeginDisabledGroup(_applyingFix);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (_results == null)
|
||||
{
|
||||
_results = new List<IntegrityIssue>();
|
||||
}
|
||||
|
||||
EditorGUILayout.TextArea("Issues Detected: " + _results.Count, EditorStyles.boldLabel);
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (_results.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No issues have been found!", MessageType.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("It is highly recommended to backup your project before using this tool.", MessageType.Warning);
|
||||
|
||||
_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, false,
|
||||
GUILayout.Width(position.width));
|
||||
|
||||
DrawIssuesList();
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
}
|
||||
|
||||
if (_applyingFix)
|
||||
{
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawIssuesList()
|
||||
{
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
for (var i = 0; i < _results.Count; i++)
|
||||
{
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
|
||||
GUILayout.Label(_results[i].Title, EditorStyles.boldLabel);
|
||||
GUILayout.Label(_results[i].Description, SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
var fixes = _results[i].GetFixes();
|
||||
if (fixes.Count > 0)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
GUILayout.Label("Possible Fixes:", EditorStyles.miniBoldLabel);
|
||||
|
||||
foreach (Fix fix in fixes)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
|
||||
GUILayout.Space(10);
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
GUILayout.Label(fix.Name, EditorStyles.boldLabel);
|
||||
|
||||
GUILayout.Label(fix.Description, SRInternalEditorUtil.Styles.ParagraphLabelItalic);
|
||||
|
||||
if (fix.IsAutoFix && GUILayout.Button("Apply Fix", GUILayout.Width(90)))
|
||||
{
|
||||
fix.Execute();
|
||||
_applyingFix = true;
|
||||
}
|
||||
|
||||
GUILayout.Space(2);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d3667acfb91436880aa7f35bcc5fe43
|
||||
timeCreated: 1611919957
|
||||
@@ -0,0 +1,707 @@
|
||||
using SRF;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
static class SRInternalEditorUtil
|
||||
{
|
||||
// Path to this file from the root path
|
||||
private const string TestPath = "SRDebugger/README.txt";
|
||||
|
||||
private static GUIStyle _bgStyle;
|
||||
private static Texture2D _logoTexture;
|
||||
private static Texture2D _welcomeLogoTexture;
|
||||
private static Texture2D _bgTexture;
|
||||
private static GUIStyle _middleAlign;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the path to the SRDebugger installation folder (e.g. Assets/StompyRobot/SRDebugger)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetRootPath()
|
||||
{
|
||||
// Find assets that match this file name
|
||||
var potentialAssets = AssetDatabase.FindAssets("README");
|
||||
|
||||
foreach (var potentialAsset in potentialAssets)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(potentialAsset);
|
||||
|
||||
if (path.Contains(TestPath))
|
||||
{
|
||||
var rootPath = Path.GetDirectoryName(path);
|
||||
return rootPath;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Unable to find SRDebugger root path. Please ensure the README file in StompyRobot/SRDebugger still exists.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the path to an SRDebugger asset relative to the installation root.
|
||||
/// </summary>
|
||||
/// <param name="relativeToRoot"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetAssetPath(string relativeToRoot)
|
||||
{
|
||||
if (!relativeToRoot.StartsWith("/"))
|
||||
{
|
||||
relativeToRoot = "/" + relativeToRoot;
|
||||
}
|
||||
|
||||
var p = GetRootPath() + relativeToRoot;
|
||||
return p;
|
||||
}
|
||||
|
||||
public static T LoadResource<T>(string path) where T : UnityEngine.Object
|
||||
{
|
||||
var p = GetAssetPath(path);
|
||||
//Debug.Log("[SRDebugger] Loading " + p);
|
||||
var asset = AssetDatabase.LoadAssetAtPath(p, typeof(T));
|
||||
return asset as T;
|
||||
}
|
||||
|
||||
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
|
||||
public enum SettingsResult
|
||||
{
|
||||
Cache,
|
||||
Loaded,
|
||||
Waiting,
|
||||
Error
|
||||
}
|
||||
|
||||
public static class EditorSettings
|
||||
{
|
||||
internal const string SettingsFilePath = "/usr/Resources/SRDebugger/Settings.asset";
|
||||
|
||||
internal const string DisabledSettingsFilePath = "/usr" + SRDebugEditor.DisabledDirectoryPostfix + "/Resources/SRDebugger/Settings.asset";
|
||||
|
||||
private static Settings _instance;
|
||||
|
||||
public static SettingsResult TryGetOrCreate(out Settings instance, out string message)
|
||||
{
|
||||
if (_instance != null)
|
||||
{
|
||||
instance = _instance;
|
||||
message = string.Empty;
|
||||
return SettingsResult.Cache;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SettingsResult result = InternalTryGetOrCreateSettings(out _instance, out message);
|
||||
instance = _instance;
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
instance = null;
|
||||
message = e.ToString();
|
||||
return SettingsResult.Error;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearCache()
|
||||
{
|
||||
Settings.ClearCache(); // Just in case runtime settings are loaded.
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var instance = _instance;
|
||||
_instance = null;
|
||||
|
||||
Resources.UnloadAsset(instance);
|
||||
instance = null;
|
||||
GC.Collect();
|
||||
|
||||
EditorUtility.UnloadUnusedAssetsImmediate();
|
||||
Resources.UnloadUnusedAssets();
|
||||
}
|
||||
|
||||
private static SettingsResult InternalTryGetOrCreateSettings(out Settings instance, out string message)
|
||||
{
|
||||
instance = null;
|
||||
message = null;
|
||||
|
||||
if (EditorApplication.isPlaying || EditorApplication.isPlayingOrWillChangePlaymode)
|
||||
{
|
||||
message = "Settings can only be modified while in edit-mode. Exit play mode to make changes to SRDebugger settings.";
|
||||
return SettingsResult.Waiting;
|
||||
}
|
||||
|
||||
// If compiling, wait for that to finish. We might be disabling/enabling SRDebugger and don't want to recreate the settings while that is in progress.
|
||||
if (EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||
{
|
||||
message = "Waiting for Unity to finish compiling/updating...";
|
||||
return SettingsResult.Waiting;
|
||||
}
|
||||
|
||||
// Check if there is a 'disabled' settings file, we don't want to create a new settings file if a disabled one exists.
|
||||
string disabledSettingsFile = SRInternalEditorUtil.GetAssetPath(DisabledSettingsFilePath);
|
||||
if (File.Exists(disabledSettingsFile))
|
||||
{
|
||||
message = "A settings file already exists but is disabled. Please ensure SRDebugger is correctly enabled or disabled.";
|
||||
return SettingsResult.Error;
|
||||
}
|
||||
|
||||
// Get resources folder path
|
||||
var settingsAssetPath = SRInternalEditorUtil.GetAssetPath(SettingsFilePath);
|
||||
|
||||
// Load existing asset.
|
||||
if (File.Exists(settingsAssetPath))
|
||||
{
|
||||
instance = AssetDatabase.LoadAssetAtPath<Settings>(settingsAssetPath);
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
message = "Error loading settings asset.";
|
||||
return SettingsResult.Error;
|
||||
}
|
||||
|
||||
return SettingsResult.Loaded;
|
||||
}
|
||||
|
||||
Debug.Log("[SRDebugger] Creating settings asset at {0}".Fmt(settingsAssetPath));
|
||||
|
||||
instance = ScriptableObject.CreateInstance<Settings>();
|
||||
|
||||
string containingDirectory = Path.GetDirectoryName(settingsAssetPath);
|
||||
if (containingDirectory == null)
|
||||
{
|
||||
message = "Error finding target settings directory.";
|
||||
return SettingsResult.Error;
|
||||
}
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
Directory.CreateDirectory(containingDirectory);
|
||||
|
||||
// Save instance if in editor
|
||||
AssetDatabase.CreateAsset(instance, settingsAssetPath);
|
||||
|
||||
return SettingsResult.Loaded;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public static Texture2D GetLogo()
|
||||
{
|
||||
if (_logoTexture != null)
|
||||
{
|
||||
return _logoTexture;
|
||||
}
|
||||
|
||||
return
|
||||
_logoTexture =
|
||||
LoadResource<Texture2D>("Editor/Logo_" + (EditorGUIUtility.isProSkin ? "DarkBG" : "LightBG") +
|
||||
".png");
|
||||
}
|
||||
|
||||
public static Texture2D GetWelcomeLogo()
|
||||
{
|
||||
if (_welcomeLogoTexture != null)
|
||||
{
|
||||
return _welcomeLogoTexture;
|
||||
}
|
||||
|
||||
return
|
||||
_welcomeLogoTexture =
|
||||
LoadResource<Texture2D>("Editor/WelcomeLogo_" +
|
||||
(EditorGUIUtility.isProSkin ? "DarkBG" : "LightBG") + ".png");
|
||||
}
|
||||
|
||||
public static Texture2D GetBackground()
|
||||
{
|
||||
if (_bgTexture != null)
|
||||
{
|
||||
return _bgTexture;
|
||||
}
|
||||
|
||||
return
|
||||
_bgTexture =
|
||||
LoadResource<Texture2D>("Editor/BG_" + (EditorGUIUtility.isProSkin ? "Dark" : "Light") + ".png");
|
||||
}
|
||||
|
||||
public static void DrawLogo(Texture2D logo)
|
||||
{
|
||||
if (logo == null)
|
||||
{
|
||||
Debug.LogError("Error loading SRDebugger logo");
|
||||
return;
|
||||
}
|
||||
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
var rect =
|
||||
#endif
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUI.DrawTexture(
|
||||
GUILayoutUtility.GetRect(logo.width, logo.width, logo.height, logo.height, GUILayout.ExpandHeight(false),
|
||||
GUILayout.ExpandWidth(false)),
|
||||
logo);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(15);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
var size = EditorStyles.miniLabel.CalcSize(new GUIContent(SRDebug.Version));
|
||||
GUI.Label(new Rect(rect.xMax - size.x, rect.yMax - size.y, size.x, size.y), SRDebug.Version,
|
||||
EditorStyles.miniLabel);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool DrawInspectorFoldout(bool isVisible, string content)
|
||||
{
|
||||
isVisible = EditorGUILayout.Foldout(isVisible, content, Styles.InspectorHeaderFoldoutStyle);
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
public static void BeginDrawBackground()
|
||||
{
|
||||
if (_bgStyle == null)
|
||||
{
|
||||
_bgStyle = new GUIStyle();
|
||||
_bgStyle.margin = _bgStyle.padding = new RectOffset(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
var rect = EditorGUILayout.BeginVertical(_bgStyle);
|
||||
|
||||
DrawTextureTiled(rect, GetBackground());
|
||||
}
|
||||
|
||||
public static void EndDrawBackground()
|
||||
{
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
public static void DrawTextureTiled(Rect rect, Texture2D tex)
|
||||
{
|
||||
GUI.BeginGroup(rect);
|
||||
|
||||
var tilesX = Mathf.Max(1, Mathf.CeilToInt(rect.width / tex.width));
|
||||
var tilesY = Mathf.Max(1, Mathf.CeilToInt(rect.height / tex.height));
|
||||
|
||||
for (var x = 0; x < tilesX; x++)
|
||||
{
|
||||
for (var y = 0; y < tilesY; y++)
|
||||
{
|
||||
var pos = new Rect(x * tex.width, y * tex.height, tex.width, tex.height);
|
||||
pos.x += rect.x;
|
||||
pos.y += rect.y;
|
||||
|
||||
GUI.DrawTexture(pos, tex, ScaleMode.ScaleAndCrop);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.EndGroup();
|
||||
}
|
||||
|
||||
public static bool ClickableLabel(string text, GUIStyle style)
|
||||
{
|
||||
var rect = EditorGUILayout.BeginVertical(Styles.NoPaddingNoMargin);
|
||||
|
||||
GUILayout.Label(text, style);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
if (Event.current.type == EventType.MouseUp && rect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
public static void DrawLayoutPreview(Rect rect, Settings settings)
|
||||
{
|
||||
const int profilerWidth = 120;
|
||||
const int profilerHeight = 70;
|
||||
const int optionsWidth = 150;
|
||||
const int optionsHeight = 36;
|
||||
|
||||
if (_middleAlign == null)
|
||||
{
|
||||
_middleAlign = new GUIStyle(EditorStyles.helpBox);
|
||||
_middleAlign.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
|
||||
var iconPath = "Editor/Icons/" + (EditorGUIUtility.isProSkin ? "Light" : "Dark");
|
||||
|
||||
const float consoleHeight = 90;
|
||||
|
||||
GUI.Box(rect, "", EditorStyles.helpBox);
|
||||
|
||||
var consoleAlignment = settings.ConsoleAlignment;
|
||||
|
||||
var consoleRect = new Rect(rect.x,
|
||||
consoleAlignment == ConsoleAlignment.Top ? rect.y : rect.yMax - consoleHeight, rect.width,
|
||||
consoleHeight);
|
||||
|
||||
GUI.Box(consoleRect, new GUIContent(LoadResource<Texture2D>(iconPath + "/console-25.png"), "Console"),
|
||||
_middleAlign);
|
||||
|
||||
var workRect = rect;
|
||||
|
||||
if (consoleAlignment == ConsoleAlignment.Top)
|
||||
{
|
||||
workRect.yMin += consoleHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
workRect.yMax -= consoleHeight;
|
||||
}
|
||||
|
||||
var opAlignment = settings.OptionsAlignment;
|
||||
var proAlignment = settings.ProfilerAlignment;
|
||||
|
||||
GUI.Box(GetAlignedRect(profilerWidth, profilerHeight, proAlignment, workRect),
|
||||
new GUIContent(LoadResource<Texture2D>(iconPath + "/profiler-25.png"), "Profiler"), _middleAlign);
|
||||
|
||||
var optionsRect = workRect;
|
||||
|
||||
if ((opAlignment == PinAlignment.TopCenter && proAlignment == PinAlignment.TopLeft) || (opAlignment == PinAlignment.BottomCenter && proAlignment == PinAlignment.BottomLeft))
|
||||
{
|
||||
optionsRect.x += profilerWidth;
|
||||
optionsRect.width -= profilerWidth;
|
||||
}
|
||||
else if ((opAlignment == PinAlignment.TopCenter && proAlignment == PinAlignment.TopRight) ||
|
||||
opAlignment == PinAlignment.BottomCenter && proAlignment == PinAlignment.BottomRight)
|
||||
{
|
||||
optionsRect.width -= profilerWidth;
|
||||
}
|
||||
|
||||
GUI.Box(GetAlignedRect(optionsWidth, optionsHeight, opAlignment, optionsRect),
|
||||
new GUIContent(LoadResource<Texture2D>(iconPath + "/options-25.png"), "Pinned Options"), _middleAlign);
|
||||
|
||||
if (settings.EnableTrigger != Settings.TriggerEnableModes.Off)
|
||||
{
|
||||
GUI.Box(GetAlignedRect(25, 25, settings.TriggerPosition, rect),
|
||||
new GUIContent("", "Entry Trigger"),
|
||||
_middleAlign);
|
||||
}
|
||||
}
|
||||
|
||||
private static Rect GetAlignedRect(int width, int height, PinAlignment alignment, Rect workRect)
|
||||
{
|
||||
var rect = new Rect(0, 0, width, height);
|
||||
|
||||
if (alignment == PinAlignment.BottomLeft || alignment == PinAlignment.BottomRight || alignment == PinAlignment.BottomCenter)
|
||||
{
|
||||
rect.position = new Vector2(0, workRect.height - rect.height);
|
||||
}
|
||||
else if (alignment == PinAlignment.CenterLeft || alignment == PinAlignment.CenterRight)
|
||||
{
|
||||
rect.position = new Vector2(0, workRect.height / 2 - rect.height / 2);
|
||||
}
|
||||
|
||||
if (alignment == PinAlignment.TopRight || alignment == PinAlignment.BottomRight || alignment == PinAlignment.CenterRight)
|
||||
{
|
||||
rect.position += new Vector2(workRect.width - rect.width, 0);
|
||||
}
|
||||
else if (alignment == PinAlignment.TopCenter || alignment == PinAlignment.BottomCenter)
|
||||
{
|
||||
rect.position += new Vector2(workRect.width / 2 - rect.width / 2, 0);
|
||||
}
|
||||
|
||||
rect.position += workRect.position;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
#endif
|
||||
public static void RenderGif(Rect pos, Texture2D map, int frameNo, int frameWidth, int frameHeight, int perLine,
|
||||
int paddingX = 0, int paddingY = 0)
|
||||
{
|
||||
var x = frameNo % perLine;
|
||||
var y = Mathf.FloorToInt((float)frameNo / perLine);
|
||||
|
||||
var xCoord = x * (frameWidth + paddingX);
|
||||
var yCoord = (y + 1) * (frameHeight + paddingY);
|
||||
|
||||
var texCoords = new Rect(
|
||||
xCoord / (float)map.width,
|
||||
(map.height - yCoord) / (float)map.height,
|
||||
(frameWidth) / (float)map.width,
|
||||
(frameHeight) / (float)map.height);
|
||||
|
||||
GUI.DrawTextureWithTexCoords(pos, map, texCoords);
|
||||
|
||||
//Debug.Log(texCoords);
|
||||
//Debug.Log("x: " + x + ", y: " + y);
|
||||
}
|
||||
|
||||
public static void DrawFooterLayout(float width)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
var margin = (EditorStyles.miniButton.padding.left) / 2f;
|
||||
width = width - margin * 2;
|
||||
|
||||
if (GUILayout.Button("Web Site", GUILayout.Width(width / 2f - margin)))
|
||||
{
|
||||
Application.OpenURL(SRDebugEditorStrings.Current.SettingsWebSiteUrl);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Asset Store Page", GUILayout.Width(width / 2f - margin)))
|
||||
{
|
||||
Application.OpenURL(SRDebugEditorStrings.Current.SettingsAssetStoreUrl);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Documentation", GUILayout.Width(width / 2f - margin)))
|
||||
{
|
||||
Application.OpenURL(SRDebugEditorStrings.Current.SettingsDocumentationUrl);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Support", GUILayout.Width(width / 2f - margin)))
|
||||
{
|
||||
Application.OpenURL(
|
||||
SRDebugEditorStrings.Current.SettingsSupportUrl);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public static class Styles
|
||||
{
|
||||
private static GUIStyle _inspectorHeaderStyle;
|
||||
private static GUIStyle _inspectorHeaderFoldoutStyle;
|
||||
private static GUIStyle _settingsHeaderBoxStyle;
|
||||
private static GUIStyle _headerLabel;
|
||||
private static GUIStyle _paragraphLabel;
|
||||
private static GUIStyle _paragraphLabelItalic;
|
||||
private static GUIStyle _radioButtonDescription;
|
||||
private static GUIStyle _radioButton;
|
||||
private static GUIStyle _leftToggleButton;
|
||||
private static GUIStyle _noPaddingNoMargin;
|
||||
private static GUIStyle _richTextLabel;
|
||||
private static GUIStyle _listBulletPoint;
|
||||
|
||||
public static string LinkColour
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
return "#7C8CB9";
|
||||
}
|
||||
|
||||
return "#0032E6";
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle InspectorHeaderStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_inspectorHeaderStyle == null)
|
||||
{
|
||||
_inspectorHeaderStyle = new GUIStyle(EditorStyles.boldLabel);
|
||||
_inspectorHeaderStyle.fontSize = 12;
|
||||
}
|
||||
|
||||
return _inspectorHeaderStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle InspectorHeaderFoldoutStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_inspectorHeaderFoldoutStyle == null)
|
||||
{
|
||||
_inspectorHeaderFoldoutStyle = new GUIStyle(EditorStyles.foldout);
|
||||
_inspectorHeaderFoldoutStyle.fontSize = 12;
|
||||
_inspectorHeaderFoldoutStyle.fontStyle = FontStyle.Bold;
|
||||
}
|
||||
|
||||
return _inspectorHeaderFoldoutStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle SettingsHeaderBoxStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_settingsHeaderBoxStyle == null)
|
||||
{
|
||||
_settingsHeaderBoxStyle = new GUIStyle("OL Title");
|
||||
_settingsHeaderBoxStyle.padding = new RectOffset(0, 0, 0, 0);
|
||||
_settingsHeaderBoxStyle.margin = new RectOffset(0, 0, 0, 0);
|
||||
_settingsHeaderBoxStyle.clipping = TextClipping.Clip;
|
||||
_settingsHeaderBoxStyle.overflow = new RectOffset(0, 0, 0, 0);
|
||||
//_settingsHeaderBoxStyle.border = new RectOffset(1, 1, 1, 1);
|
||||
_settingsHeaderBoxStyle.fixedHeight = 0.5f;
|
||||
}
|
||||
|
||||
return _settingsHeaderBoxStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle HeaderLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_headerLabel == null)
|
||||
{
|
||||
_headerLabel = new GUIStyle(EditorStyles.largeLabel);
|
||||
_headerLabel.fontSize = 18;
|
||||
_headerLabel.fontStyle = FontStyle.Normal;
|
||||
_headerLabel.margin = new RectOffset(5, 5, 5, 5);
|
||||
}
|
||||
|
||||
return _headerLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle ParagraphLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_paragraphLabel == null)
|
||||
{
|
||||
_paragraphLabel = new GUIStyle(EditorStyles.label);
|
||||
_paragraphLabel.margin = new RectOffset(5, 5, 5, 5);
|
||||
_paragraphLabel.wordWrap = true;
|
||||
_paragraphLabel.richText = true;
|
||||
}
|
||||
|
||||
return _paragraphLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle ParagraphLabelItalic
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_paragraphLabelItalic == null)
|
||||
{
|
||||
_paragraphLabelItalic = new GUIStyle(EditorStyles.label);
|
||||
_paragraphLabelItalic.margin = new RectOffset(5, 5, 5, 5);
|
||||
_paragraphLabelItalic.wordWrap = true;
|
||||
_paragraphLabelItalic.richText = true;
|
||||
_paragraphLabelItalic.fontStyle = FontStyle.Italic;
|
||||
}
|
||||
|
||||
return _paragraphLabelItalic;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle LeftToggleButton
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_leftToggleButton == null)
|
||||
{
|
||||
_leftToggleButton = new GUIStyle(EditorStyles.label);
|
||||
_leftToggleButton.contentOffset = new Vector2(_leftToggleButton.contentOffset.x + 5,
|
||||
_leftToggleButton.contentOffset.y);
|
||||
}
|
||||
|
||||
return _leftToggleButton;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle RadioButton
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_radioButton == null)
|
||||
{
|
||||
_radioButton = new GUIStyle(EditorStyles.radioButton);
|
||||
_radioButton.contentOffset = new Vector2(_radioButton.contentOffset.x + 5,
|
||||
_radioButton.contentOffset.y);
|
||||
}
|
||||
|
||||
return _radioButton;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle RadioButtonDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_radioButtonDescription == null)
|
||||
{
|
||||
_radioButtonDescription = new GUIStyle(ParagraphLabel);
|
||||
_radioButtonDescription.padding.left = (int)RadioButton.contentOffset.x +
|
||||
RadioButton.padding.left;
|
||||
}
|
||||
|
||||
return _radioButtonDescription;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle NoPaddingNoMargin
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_noPaddingNoMargin == null)
|
||||
{
|
||||
_noPaddingNoMargin = new GUIStyle();
|
||||
_noPaddingNoMargin.margin = new RectOffset(0, 0, 0, 0);
|
||||
_noPaddingNoMargin.padding = new RectOffset(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
return _noPaddingNoMargin;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle RichTextLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_richTextLabel == null)
|
||||
{
|
||||
_richTextLabel = new GUIStyle(EditorStyles.label);
|
||||
_richTextLabel.richText = true;
|
||||
_richTextLabel.margin = new RectOffset(2, 2, 0, 0);
|
||||
}
|
||||
|
||||
return _richTextLabel;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle ListBulletPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_listBulletPoint == null)
|
||||
{
|
||||
_listBulletPoint = new GUIStyle(EditorStyles.miniBoldLabel);
|
||||
_listBulletPoint.wordWrap = true;
|
||||
_listBulletPoint.margin = new RectOffset(6, 2, 0, 0);
|
||||
}
|
||||
|
||||
return _listBulletPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f05cd73b58c9481593f90b04c3084b15
|
||||
timeCreated: 1611414371
|
||||
@@ -0,0 +1,455 @@
|
||||
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SRF;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.ComponentModel;
|
||||
using SRF.Helpers;
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
using Internal;
|
||||
using SRDebugger.Services;
|
||||
using UI.Controls.Data;
|
||||
#endif
|
||||
|
||||
class SROptionsWindow : EditorWindow
|
||||
{
|
||||
[MenuItem(SRDebugEditorPaths.SROptionsMenuItemPath)]
|
||||
public static void Open()
|
||||
{
|
||||
var window = GetWindow<SROptionsWindow>(false, "SROptions", true);
|
||||
window.minSize = new Vector2(100, 100);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
#if DISABLE_SRDEBUGGER
|
||||
private bool _isWorking;
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
SRDebugEditor.DrawDisabledWindowGui(ref _isWorking);
|
||||
}
|
||||
#else
|
||||
[Serializable]
|
||||
private class CategoryState
|
||||
{
|
||||
public string Name;
|
||||
public bool IsOpen;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<CategoryState> _categoryStates = new List<CategoryState>();
|
||||
|
||||
private Dictionary<Type, Action<OptionDefinition>> _typeLookup;
|
||||
private Dictionary<string, List<OptionDefinition>> _options;
|
||||
|
||||
private Vector2 _scrollPosition;
|
||||
private bool _queueRefresh;
|
||||
private bool _isDirty;
|
||||
|
||||
|
||||
[NonSerialized] private GUIStyle _divider;
|
||||
[NonSerialized] private GUIStyle _foldout;
|
||||
|
||||
private IOptionsService _activeOptionsService;
|
||||
|
||||
public void OnInspectorUpdate()
|
||||
{
|
||||
if (EditorApplication.isPlaying && (_options == null || _isDirty))
|
||||
{
|
||||
Populate();
|
||||
_queueRefresh = true;
|
||||
_isDirty = false;
|
||||
}
|
||||
else if (!EditorApplication.isPlaying && _options != null)
|
||||
{
|
||||
Clear();
|
||||
_queueRefresh = true;
|
||||
}
|
||||
|
||||
if (_queueRefresh)
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
|
||||
_queueRefresh = false;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void PopulateTypeLookup()
|
||||
{
|
||||
_typeLookup = new Dictionary<Type, Action<OptionDefinition>>()
|
||||
{
|
||||
{typeof(int), OnGUI_Int},
|
||||
{typeof(float), OnGUI_Float},
|
||||
{typeof(double), OnGUI_Double},
|
||||
{typeof(string), OnGUI_String},
|
||||
{typeof(bool), OnGUI_Boolean },
|
||||
{typeof(uint), OnGUI_AnyInteger},
|
||||
{typeof(ushort), OnGUI_AnyInteger},
|
||||
{typeof(short), OnGUI_AnyInteger},
|
||||
{typeof(sbyte), OnGUI_AnyInteger},
|
||||
{typeof(byte), OnGUI_AnyInteger},
|
||||
{typeof(long), OnGUI_AnyInteger},
|
||||
};
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
_options = null;
|
||||
_isDirty = false;
|
||||
|
||||
if (_activeOptionsService != null)
|
||||
{
|
||||
_activeOptionsService.OptionsUpdated -= OnOptionsUpdated;
|
||||
}
|
||||
|
||||
_activeOptionsService = null;
|
||||
}
|
||||
|
||||
void Populate()
|
||||
{
|
||||
if (_typeLookup == null)
|
||||
{
|
||||
PopulateTypeLookup();
|
||||
}
|
||||
|
||||
if (_activeOptionsService != null)
|
||||
{
|
||||
_activeOptionsService.OptionsUpdated -= OnOptionsUpdated;
|
||||
}
|
||||
|
||||
if (_options != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, List<OptionDefinition>> kv in _options)
|
||||
{
|
||||
foreach (var option in kv.Value)
|
||||
{
|
||||
if (option.IsProperty)
|
||||
{
|
||||
option.Property.ValueChanged -= OnOptionPropertyValueChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_options = new Dictionary<string, List<OptionDefinition>>();
|
||||
|
||||
foreach (var option in Service.Options.Options)
|
||||
{
|
||||
List<OptionDefinition> list;
|
||||
|
||||
if (!_options.TryGetValue(option.Category, out list))
|
||||
{
|
||||
list = new List<OptionDefinition>();
|
||||
_options[option.Category] = list;
|
||||
}
|
||||
|
||||
list.Add(option);
|
||||
|
||||
if (option.IsProperty)
|
||||
{
|
||||
option.Property.ValueChanged += OnOptionPropertyValueChanged;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in _options)
|
||||
{
|
||||
kv.Value.Sort((d1, d2) => d1.SortPriority.CompareTo(d2.SortPriority));
|
||||
}
|
||||
|
||||
_activeOptionsService = Service.Options;
|
||||
_activeOptionsService.OptionsUpdated += OnOptionsUpdated;
|
||||
}
|
||||
|
||||
private void OnOptionPropertyValueChanged(PropertyReference property)
|
||||
{
|
||||
_queueRefresh = true;
|
||||
}
|
||||
|
||||
private void OnOptionsUpdated(object sender, EventArgs e)
|
||||
{
|
||||
_isDirty = true;
|
||||
_queueRefresh = true;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (!EditorApplication.isPlayingOrWillChangePlaymode || _options == null)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Label("SROptions can only be edited in play-mode.");
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_divider == null)
|
||||
{
|
||||
_divider = new GUIStyle(GUI.skin.box);
|
||||
_divider.stretchWidth = true;
|
||||
_divider.fixedHeight = 2;
|
||||
}
|
||||
|
||||
if (_foldout == null)
|
||||
{
|
||||
_foldout = new GUIStyle(EditorStyles.foldout);
|
||||
_foldout.fontStyle = FontStyle.Bold;
|
||||
}
|
||||
|
||||
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
|
||||
|
||||
foreach (var kv in _options)
|
||||
{
|
||||
var state = _categoryStates.FirstOrDefault(p => p.Name == kv.Key);
|
||||
|
||||
if (state == null)
|
||||
{
|
||||
state = new CategoryState()
|
||||
{
|
||||
Name = kv.Key,
|
||||
IsOpen = true
|
||||
};
|
||||
_categoryStates.Add(state);
|
||||
}
|
||||
|
||||
state.IsOpen = EditorGUILayout.Foldout(state.IsOpen, kv.Key, _foldout);
|
||||
|
||||
if (!state.IsOpen)
|
||||
continue;
|
||||
|
||||
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
|
||||
OnGUI_Category(kv.Value);
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
void OnGUI_Category(List<OptionDefinition> options)
|
||||
{
|
||||
for (var i = 0; i < options.Count; i++)
|
||||
{
|
||||
var op = options[i];
|
||||
|
||||
if (op.Property != null)
|
||||
{
|
||||
OnGUI_Property(op);
|
||||
} else if (op.Method != null)
|
||||
{
|
||||
OnGUI_Method(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Method(OptionDefinition op)
|
||||
{
|
||||
if (GUILayout.Button(op.Name))
|
||||
{
|
||||
op.Method.Invoke(null);
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Property(OptionDefinition op)
|
||||
{
|
||||
Action<OptionDefinition> method;
|
||||
|
||||
if (op.Property.PropertyType.IsEnum)
|
||||
{
|
||||
method = OnGUI_Enum;
|
||||
}
|
||||
else if (!_typeLookup.TryGetValue(op.Property.PropertyType, out method))
|
||||
{
|
||||
OnGUI_Unsupported(op);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!op.Property.CanWrite)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
}
|
||||
|
||||
method(op);
|
||||
|
||||
if (!op.Property.CanWrite)
|
||||
{
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_String(OptionDefinition op)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var newValue = EditorGUILayout.TextField(op.Name, (string) op.Property.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Boolean(OptionDefinition op)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var newValue = EditorGUILayout.Toggle(op.Name, (bool) op.Property.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Enum(OptionDefinition op)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var newValue = EditorGUILayout.EnumPopup(op.Name, (Enum)op.Property.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Int(OptionDefinition op)
|
||||
{
|
||||
var range = op.Property.GetAttribute<NumberRangeAttribute>();
|
||||
|
||||
int newValue;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (range != null)
|
||||
{
|
||||
newValue = EditorGUILayout.IntSlider(op.Name, (int)op.Property.GetValue(), (int)range.Min, (int)range.Max);
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = EditorGUILayout.IntField(op.Name, (int) op.Property.GetValue());
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Float(OptionDefinition op)
|
||||
{
|
||||
var range = op.Property.GetAttribute<NumberRangeAttribute>();
|
||||
|
||||
float newValue;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (range != null)
|
||||
{
|
||||
newValue = EditorGUILayout.Slider(op.Name, (float)op.Property.GetValue(), (float)range.Min, (float)range.Max);
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = EditorGUILayout.FloatField(op.Name, (float) op.Property.GetValue());
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Double(OptionDefinition op)
|
||||
{
|
||||
var range = op.Property.GetAttribute<NumberRangeAttribute>();
|
||||
|
||||
double newValue;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (range != null && range.Min > float.MinValue && range.Max < float.MaxValue)
|
||||
{
|
||||
newValue = EditorGUILayout.Slider(op.Name, (float)op.Property.GetValue(), (float)range.Min, (float)range.Max);
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = EditorGUILayout.DoubleField(op.Name, (double) op.Property.GetValue());
|
||||
|
||||
if (range != null)
|
||||
{
|
||||
if (newValue > range.Max)
|
||||
{
|
||||
newValue = range.Max;
|
||||
} else if (newValue < range.Min)
|
||||
{
|
||||
newValue = range.Min;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OnGUI_AnyInteger(OptionDefinition op)
|
||||
{
|
||||
NumberControl.ValueRange range;
|
||||
|
||||
if (!NumberControl.ValueRanges.TryGetValue(op.Property.PropertyType, out range))
|
||||
{
|
||||
Debug.LogError("Unknown integer type: " + op.Property.PropertyType);
|
||||
return;
|
||||
}
|
||||
|
||||
var userRange = op.Property.GetAttribute<NumberRangeAttribute>();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var oldValue = (long)Convert.ChangeType(op.Property.GetValue(), typeof(long));
|
||||
var newValue = EditorGUILayout.LongField(op.Name, oldValue);
|
||||
|
||||
if (newValue > range.MaxValue)
|
||||
{
|
||||
newValue = (long)range.MaxValue;
|
||||
} else if (newValue < range.MinValue)
|
||||
{
|
||||
newValue = (long)range.MinValue;
|
||||
}
|
||||
|
||||
if (userRange != null)
|
||||
{
|
||||
if (newValue > userRange.Max)
|
||||
{
|
||||
newValue = (long)userRange.Max;
|
||||
} else if (newValue < userRange.Min)
|
||||
{
|
||||
newValue = (long) userRange.Min;
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI_Unsupported(OptionDefinition op)
|
||||
{
|
||||
EditorGUILayout.PrefixLabel(op.Name);
|
||||
EditorGUILayout.LabelField("Unsupported Type: {0}".Fmt(op.Property.PropertyType));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c10ec5c3e9f1e404ba655cbc07340b94
|
||||
timeCreated: 1465649914
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
[CustomEditor(typeof (Settings))]
|
||||
class SettingsEditor : UnityEditor.Editor
|
||||
{
|
||||
private bool _override;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
SRInternalEditorUtil.DrawLogo(SRInternalEditorUtil.GetLogo());
|
||||
|
||||
GUILayout.Label(
|
||||
"This asset contains the runtime settings used by SRDebugger. It is recommended that this asset be edited only via the SRDebugger Settings window.",
|
||||
EditorStyles.wordWrappedLabel);
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (GUILayout.Button("Open SRDebugger Settings Window"))
|
||||
{
|
||||
SRDebuggerSettingsWindow.Open();
|
||||
}
|
||||
|
||||
if (!_override)
|
||||
{
|
||||
if (GUILayout.Button("Override Warning"))
|
||||
{
|
||||
_override = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label(
|
||||
"You have been warned...",
|
||||
EditorStyles.wordWrappedLabel);
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (_override)
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6304f38f53dfcc44f9265410f0f14050
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
1026
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor/SettingsWindow.cs
Normal file
1026
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Editor/SettingsWindow.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a6cf957f3eda7b429dd0eae2cfbb40c
|
||||
timeCreated: 1441902550
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "StompyRobot.SRDebugger.Editor",
|
||||
"references": [
|
||||
"StompyRobot.SRDebugger",
|
||||
"StompyRobot.SRF"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07ab30a82c1032d45ad726f7216628e8
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,194 @@
|
||||
#if !DISABLE_SRDEBUGGER
|
||||
using SRF;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
class WelcomeWindow : EditorWindow
|
||||
{
|
||||
private const string WelcomeWindowPlayerPrefsKey = "SRDEBUGGER_WELCOME_SHOWN_VERSION";
|
||||
private Texture2D _demoSprite;
|
||||
private Vector2 _scrollPosition;
|
||||
|
||||
static WelcomeWindow()
|
||||
{
|
||||
EditorApplication.update += OpenUpdate;
|
||||
}
|
||||
|
||||
private static void OpenUpdate()
|
||||
{
|
||||
if (ShouldOpen())
|
||||
{
|
||||
Open();
|
||||
}
|
||||
|
||||
EditorApplication.update -= OpenUpdate;
|
||||
}
|
||||
|
||||
[MenuItem(SRDebugEditorPaths.WelcomeItemPath)]
|
||||
public static void Open()
|
||||
{
|
||||
GetWindowWithRect<WelcomeWindow>(new Rect(0, 0, 449, 500), true, "SRDebugger - Welcome", true);
|
||||
}
|
||||
|
||||
private static bool ShouldOpen()
|
||||
{
|
||||
var settings = Settings.GetInstance();
|
||||
if (settings != null)
|
||||
{
|
||||
if (settings.DisableWelcomePopup)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var hasKey = EditorPrefs.HasKey(WelcomeWindowPlayerPrefsKey);
|
||||
|
||||
if (!hasKey)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var value = EditorPrefs.GetString(WelcomeWindowPlayerPrefsKey);
|
||||
|
||||
if (value != SRDebug.Version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
EditorPrefs.SetString(WelcomeWindowPlayerPrefsKey, SRDebug.Version);
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// Draw header area
|
||||
SRInternalEditorUtil.BeginDrawBackground();
|
||||
SRInternalEditorUtil.DrawLogo(SRInternalEditorUtil.GetWelcomeLogo());
|
||||
SRInternalEditorUtil.EndDrawBackground();
|
||||
|
||||
// Draw header/content divider
|
||||
EditorGUILayout.BeginVertical(SRInternalEditorUtil.Styles.SettingsHeaderBoxStyle);
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
|
||||
|
||||
GUILayout.Label("Welcome", SRInternalEditorUtil.Styles.HeaderLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"Thank you for purchasing SRDebugger, your support is very much appreciated and we hope you find it useful for your project. " +
|
||||
"This window contains a quick guide to get to help get you started with SRDebugger.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
if (SRInternalEditorUtil.ClickableLabel(
|
||||
"Note: For more detailed information <color={0}>click here</color> to visit the online documentation."
|
||||
.Fmt(SRInternalEditorUtil.Styles.LinkColour),
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel))
|
||||
{
|
||||
Application.OpenURL(SRDebugEditorStrings.Current.SettingsDocumentationUrl);
|
||||
}
|
||||
|
||||
GUILayout.Label("Quick Start", SRInternalEditorUtil.Styles.HeaderLabel);
|
||||
GUILayout.Label(
|
||||
"Now that you have imported the package, you should find the trigger available in the top-left of your game window when in play mode. " +
|
||||
"Triple-clicking this trigger will bring up the debug panel. The trigger is hidden until clicked.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"By default, SRDebugger loads automatically when your game starts. " +
|
||||
"You can change this behaviour from the SRDebugger Settings window.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
DrawVideo();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
GUILayout.Label("Customization", SRInternalEditorUtil.Styles.HeaderLabel);
|
||||
|
||||
if (SRInternalEditorUtil.ClickableLabel(
|
||||
"Many features of SRDebugger can be configured from the <color={0}>SRDebugger Settings</color> window."
|
||||
.Fmt(
|
||||
SRInternalEditorUtil.Styles.LinkColour), SRInternalEditorUtil.Styles.ParagraphLabel))
|
||||
{
|
||||
SRDebuggerSettingsWindow.Open();
|
||||
}
|
||||
|
||||
GUILayout.Label(
|
||||
"From the settings window you can configure loading behaviour, trigger position, docked tools layout, and more. " +
|
||||
"You can enable the bug reporter service by using the sign-up form to get a free API key.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.Label("What Next?", SRInternalEditorUtil.Styles.HeaderLabel);
|
||||
|
||||
if (SRInternalEditorUtil.ClickableLabel(
|
||||
"For more detailed information about SRDebugger's features or details about the Options Tab and script API, check the <color={0}>online documentation</color>."
|
||||
.Fmt(SRInternalEditorUtil.Styles.LinkColour), SRInternalEditorUtil.Styles.ParagraphLabel))
|
||||
{
|
||||
Application.OpenURL(SRDebugEditorStrings.Current.SettingsDocumentationUrl);
|
||||
}
|
||||
|
||||
GUILayout.Label(
|
||||
"Thanks again for purchasing SRDebugger. " +
|
||||
"If you find it useful please consider leaving a rating or review on the Asset Store page as this helps us continue to provide updates and support to our users. ",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
GUILayout.Label(
|
||||
"If you have any questions or concerns please do not hesitate to get in touch with us via email or the Unity forums.",
|
||||
SRInternalEditorUtil.Styles.ParagraphLabel);
|
||||
|
||||
SRInternalEditorUtil.DrawFooterLayout(position.width - 15);
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void DrawVideo()
|
||||
{
|
||||
if (_demoSprite == null)
|
||||
{
|
||||
_demoSprite = SRInternalEditorUtil.LoadResource<Texture2D>("Editor/DemoSprite.png");
|
||||
}
|
||||
|
||||
if (_demoSprite == null)
|
||||
return;
|
||||
|
||||
var frameWidth = 400;
|
||||
var frameHeight = 300;
|
||||
var framePadding = 0;
|
||||
var extraFramesStart = 5;
|
||||
var extraFramesEnd = 20;
|
||||
var totalFrames = 29;
|
||||
var fps = 16f;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
var rect = GUILayoutUtility.GetRect(400*0.75f, 300*0.75f, GUILayout.ExpandHeight(false),
|
||||
GUILayout.ExpandWidth(false));
|
||||
|
||||
var frame = ((int) (EditorApplication.timeSinceStartup*fps))%
|
||||
(totalFrames + extraFramesStart + extraFramesEnd);
|
||||
frame -= extraFramesStart;
|
||||
|
||||
var actualFrame = Mathf.Clamp(frame, 0, totalFrames);
|
||||
|
||||
SRInternalEditorUtil.RenderGif(rect, _demoSprite, actualFrame, frameWidth, frameHeight, 5, framePadding,
|
||||
framePadding);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e35f7047e81c2247ae9a5bfd682e156
|
||||
timeCreated: 1442417928
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SRDebugger.Services;
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
public class BugReport
|
||||
{
|
||||
public List<ConsoleEntry> ConsoleLog;
|
||||
|
||||
/// <summary>
|
||||
/// User-entered email address
|
||||
/// </summary>
|
||||
public string Email;
|
||||
|
||||
/// <summary>
|
||||
/// Raw data of the captured screenshot (png)
|
||||
/// </summary>
|
||||
public byte[] ScreenshotData;
|
||||
|
||||
public Dictionary<string, Dictionary<string, object>> SystemInformation;
|
||||
|
||||
public string UserDescription;
|
||||
}
|
||||
|
||||
public sealed class BugReportSubmitResult
|
||||
{
|
||||
public static BugReportSubmitResult Success
|
||||
{
|
||||
get { return new BugReportSubmitResult(true, null); }
|
||||
}
|
||||
|
||||
public static BugReportSubmitResult Error(string errorMessage)
|
||||
{
|
||||
return new BugReportSubmitResult(false, errorMessage);
|
||||
}
|
||||
|
||||
public bool IsSuccessful { get; }
|
||||
|
||||
public string ErrorMessage { get; }
|
||||
|
||||
private BugReportSubmitResult(bool successful, string error)
|
||||
{
|
||||
IsSuccessful = successful;
|
||||
ErrorMessage = error;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IBugReporterHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if this bug reporter handler is able to be used.
|
||||
/// If false, the bug reporter tab will be hidden.
|
||||
/// </summary>
|
||||
bool IsUsable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Submit a new bug report to the handler.
|
||||
/// </summary>
|
||||
/// <param name="report">The report to be submitted.</param>
|
||||
/// <param name="onComplete">Action to be invoked when the bug report is completed.</param>
|
||||
/// <param name="progress">Callback to set the current submit progress.</param>
|
||||
void Submit(BugReport report, Action<BugReportSubmitResult> onComplete, IProgress<float> progress);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28437d02794549d4fa4a84f60ad80a88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
/// <summary>
|
||||
/// You can implement this interface to create a dynamic "options container".
|
||||
/// Add the container to SRDebugger via the SRDebug API.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When the container is added via the API, the initial set of options will be fetched via <see cref="GetOptions"/>.
|
||||
/// Options that are added or removed after this point must fire the <see cref="OptionAdded"/> and <see cref="OptionRemoved"/> events in order
|
||||
/// for those options to be added/removed from the debug panel.
|
||||
/// If you do not intend to fire any events (i.e. this is a static container) then <see cref="IsDynamic"/> should return false.
|
||||
/// </remarks>
|
||||
public interface IOptionContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the initial set of options contained in this object.
|
||||
/// </summary>
|
||||
IEnumerable<OptionDefinition> GetOptions();
|
||||
|
||||
/// <summary>
|
||||
/// Will the options collection be changed via events?
|
||||
/// If true, changes to the option set can be provided via the events <see cref="OptionAdded"/> and <see cref="OptionRemoved"/>.
|
||||
/// If false, the events will be ignored.
|
||||
/// </summary>
|
||||
bool IsDynamic { get; }
|
||||
|
||||
event Action<OptionDefinition> OptionAdded;
|
||||
event Action<OptionDefinition> OptionRemoved;
|
||||
}
|
||||
|
||||
public sealed class DynamicOptionContainer : IOptionContainer
|
||||
{
|
||||
public IList<OptionDefinition> Options
|
||||
{
|
||||
get { return _optionsReadOnly; }
|
||||
}
|
||||
|
||||
private readonly List<OptionDefinition> _options = new List<OptionDefinition>();
|
||||
private readonly IList<OptionDefinition> _optionsReadOnly;
|
||||
|
||||
public DynamicOptionContainer()
|
||||
{
|
||||
_optionsReadOnly = _options.AsReadOnly();
|
||||
}
|
||||
|
||||
public void AddOption(OptionDefinition option)
|
||||
{
|
||||
_options.Add(option);
|
||||
|
||||
if (OptionAdded != null)
|
||||
{
|
||||
OptionAdded(option);
|
||||
}
|
||||
}
|
||||
|
||||
public bool RemoveOption(OptionDefinition option)
|
||||
{
|
||||
if (_options.Remove(option))
|
||||
{
|
||||
if (OptionRemoved != null)
|
||||
{
|
||||
OptionRemoved(option);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IEnumerable<OptionDefinition> IOptionContainer.GetOptions()
|
||||
{
|
||||
return _options;
|
||||
}
|
||||
|
||||
public bool IsDynamic
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public event Action<OptionDefinition> OptionAdded;
|
||||
public event Action<OptionDefinition> OptionRemoved;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4ed420ab79c4165a7b6422bd1ee91d5
|
||||
timeCreated: 1609338293
|
||||
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal.meta
Normal file
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 719f45e4748815645b1df26fc728ed66
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
16
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Api.cs
Normal file
16
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Api.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
public static class SRDebugApi
|
||||
{
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
public const string Protocol = "https://";
|
||||
#else
|
||||
public const string Protocol = "http://";
|
||||
#endif
|
||||
|
||||
public const string EndPoint = Protocol + "srdebugger.stompyrobot.uk";
|
||||
|
||||
public const string BugReportEndPoint = EndPoint + "/report/submit";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a0f930eb7b829c40a5ba3024eed594d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,96 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using SRF;
|
||||
|
||||
public static class SRDebugApiUtil
|
||||
{
|
||||
public static string ParseErrorException(WebException ex)
|
||||
{
|
||||
if (ex.Response == null)
|
||||
{
|
||||
return ex.Message;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = ReadResponseStream(ex.Response);
|
||||
|
||||
return ParseErrorResponse(response);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ParseErrorResponse(string response, string fallback = "Unexpected Response")
|
||||
{
|
||||
try
|
||||
{
|
||||
var jsonTable = (Dictionary<string, object>) Json.Deserialize(response);
|
||||
|
||||
var error = "";
|
||||
|
||||
error += jsonTable["errorMessage"];
|
||||
|
||||
object value;
|
||||
|
||||
if (jsonTable.TryGetValue("errors", out value) && value is IList<object>)
|
||||
{
|
||||
var errors = value as IList<object>;
|
||||
|
||||
foreach (var e in errors)
|
||||
{
|
||||
error += "\n";
|
||||
error += e;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (response.Contains("<html>"))
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR || (!NETFX_CORE && !UNITY_WINRT)
|
||||
|
||||
public static bool ReadResponse(HttpWebRequest request, out string result)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = request.GetResponse();
|
||||
result = ReadResponseStream(response);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
result = ParseErrorException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static string ReadResponseStream(WebResponse stream)
|
||||
{
|
||||
using (var responseSteam = stream.GetResponseStream())
|
||||
{
|
||||
using (var streamReader = new StreamReader(responseSteam))
|
||||
{
|
||||
return streamReader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f41e06622aa4979458cf59f1a355095a
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,189 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using SRF;
|
||||
using UnityEngine;
|
||||
using System.Text;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
class BugReportApi : MonoBehaviour
|
||||
{
|
||||
private string _apiKey;
|
||||
private BugReport _bugReport;
|
||||
private bool _isBusy;
|
||||
|
||||
private UnityWebRequest _webRequest;
|
||||
private Action<BugReportSubmitResult> _onComplete;
|
||||
private IProgress<float> _progress;
|
||||
|
||||
public static void Submit(BugReport report, string apiKey, Action<BugReportSubmitResult> onComplete, IProgress<float> progress)
|
||||
{
|
||||
var go = new GameObject("BugReportApi");
|
||||
go.transform.parent = Hierarchy.Get("SRDebugger");
|
||||
|
||||
var bugReportApi = go.AddComponent<BugReportApi>();
|
||||
bugReportApi.Init(report, apiKey, onComplete, progress);
|
||||
bugReportApi.StartCoroutine(bugReportApi.Submit());
|
||||
}
|
||||
|
||||
private void Init(BugReport report, string apiKey, Action<BugReportSubmitResult> onComplete, IProgress<float> progress)
|
||||
{
|
||||
_bugReport = report;
|
||||
_apiKey = apiKey;
|
||||
_onComplete = onComplete;
|
||||
_progress = progress;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_isBusy && _webRequest != null)
|
||||
{
|
||||
_progress.Report(_webRequest.uploadProgress);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator Submit()
|
||||
{
|
||||
if (_isBusy)
|
||||
{
|
||||
throw new InvalidOperationException("BugReportApi is already sending a bug report");
|
||||
}
|
||||
|
||||
// Reset state
|
||||
_isBusy = true;
|
||||
_webRequest = null;
|
||||
|
||||
string json;
|
||||
byte[] jsonBytes;
|
||||
|
||||
try
|
||||
{
|
||||
json = BuildJsonRequest(_bugReport);
|
||||
jsonBytes = Encoding.UTF8.GetBytes(json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
SetCompletionState(BugReportSubmitResult.Error("Error building bug report."));
|
||||
yield break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const string jsonContentType = "application/json";
|
||||
|
||||
_webRequest = new UnityWebRequest(SRDebugApi.BugReportEndPoint, UnityWebRequest.kHttpVerbPOST,
|
||||
new DownloadHandlerBuffer(), new UploadHandlerRaw(jsonBytes)
|
||||
{
|
||||
contentType = jsonContentType
|
||||
});
|
||||
_webRequest.SetRequestHeader("Accept", jsonContentType);
|
||||
_webRequest.SetRequestHeader("X-ApiKey", _apiKey);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(e);
|
||||
|
||||
if (_webRequest != null)
|
||||
{
|
||||
_webRequest.Dispose();
|
||||
_webRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (_webRequest == null)
|
||||
{
|
||||
SetCompletionState(BugReportSubmitResult.Error("Error building bug report request."));
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return _webRequest.SendWebRequest();
|
||||
|
||||
#if UNITY_2018 || UNITY_2019
|
||||
bool isError = _webRequest.isNetworkError;
|
||||
#else
|
||||
bool isError = _webRequest.result == UnityWebRequest.Result.ConnectionError || _webRequest.result == UnityWebRequest.Result.DataProcessingError;
|
||||
#endif
|
||||
|
||||
if (isError)
|
||||
{
|
||||
SetCompletionState(BugReportSubmitResult.Error("Request Error: " + _webRequest.error));
|
||||
_webRequest.Dispose();
|
||||
yield break;
|
||||
}
|
||||
|
||||
long responseCode = _webRequest.responseCode;
|
||||
var responseJson = _webRequest.downloadHandler.text;
|
||||
|
||||
_webRequest.Dispose();
|
||||
|
||||
if (responseCode != 200)
|
||||
{
|
||||
SetCompletionState(BugReportSubmitResult.Error("Server: " + SRDebugApiUtil.ParseErrorResponse(responseJson, "Unknown response from server")));
|
||||
yield break;
|
||||
}
|
||||
|
||||
SetCompletionState(BugReportSubmitResult.Success);
|
||||
}
|
||||
|
||||
private void SetCompletionState(BugReportSubmitResult result)
|
||||
{
|
||||
_bugReport.ScreenshotData = null; // Clear the heaviest data in case something holds onto it
|
||||
_isBusy = false;
|
||||
|
||||
if (!result.IsSuccessful)
|
||||
{
|
||||
Debug.LogError("Bug Reporter Error: " + result.ErrorMessage);
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
_onComplete(result);
|
||||
}
|
||||
|
||||
private static string BuildJsonRequest(BugReport report)
|
||||
{
|
||||
var ht = new Hashtable();
|
||||
|
||||
ht.Add("userEmail", report.Email);
|
||||
ht.Add("userDescription", report.UserDescription);
|
||||
|
||||
ht.Add("console", CreateConsoleDump());
|
||||
ht.Add("systemInformation", report.SystemInformation);
|
||||
ht.Add("applicationIdentifier", Application.identifier);
|
||||
|
||||
if (report.ScreenshotData != null)
|
||||
{
|
||||
ht.Add("screenshot", Convert.ToBase64String(report.ScreenshotData));
|
||||
}
|
||||
var json = Json.Serialize(ht);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private static List<List<string>> CreateConsoleDump()
|
||||
{
|
||||
var consoleLog = Service.Console.AllEntries;
|
||||
var list = new List<List<string>>(consoleLog.Count);
|
||||
|
||||
foreach (var consoleEntry in consoleLog)
|
||||
{
|
||||
var entry = new List<string>(5);
|
||||
|
||||
entry.Add(consoleEntry.LogType.ToString());
|
||||
entry.Add(consoleEntry.Message);
|
||||
entry.Add(consoleEntry.StackTrace);
|
||||
|
||||
if (consoleEntry.Count > 1)
|
||||
{
|
||||
entry.Add(consoleEntry.Count.ToString());
|
||||
}
|
||||
|
||||
list.Add(entry);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfdfb4c8f27446b4d8aa88d3980f4c50
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
public class BugReportScreenshotUtil
|
||||
{
|
||||
public static byte[] ScreenshotData;
|
||||
|
||||
public static IEnumerator ScreenshotCaptureCo()
|
||||
{
|
||||
if (ScreenshotData != null)
|
||||
{
|
||||
Debug.LogWarning("[SRDebugger] Warning, overriding existing screenshot data.");
|
||||
}
|
||||
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
var tex = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
|
||||
|
||||
tex.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
|
||||
tex.Apply();
|
||||
|
||||
ScreenshotData = tex.EncodeToPNG();
|
||||
|
||||
Object.Destroy(tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52ead462624dc0c4d80e12ce55109a26
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
----------------------------------------------------------------------------
|
||||
"THE BEER-WARE LICENSE" (Revision 42):
|
||||
Joao Portela wrote this file. As long as you retain this notice you
|
||||
can do whatever you want with this stuff. If we meet some day, and you think
|
||||
this stuff is worth it, you can buy me a beer in return.
|
||||
Joao Portela
|
||||
--------------------------------------------------------------------------
|
||||
* https://github.com/joaoportela/CircullarBuffer-CSharp
|
||||
*/
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Circular buffer.
|
||||
/// When writting to a full buffer:
|
||||
/// PushBack -> removes this[0] / Front()
|
||||
/// PushFront -> removes this[Size-1] / Back()
|
||||
/// this implementation is inspired by
|
||||
/// http://www.boost.org/doc/libs/1_53_0/libs/circular_buffer/doc/circular_buffer.html
|
||||
/// because I liked their interface.
|
||||
/// </summary>
|
||||
public class CircularBuffer<T> : IEnumerable<T>, IReadOnlyList<T>
|
||||
{
|
||||
private readonly T[] _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// The _end. Index after the last element in the buffer.
|
||||
/// </summary>
|
||||
private int _end;
|
||||
|
||||
/// <summary>
|
||||
/// The _size. Buffer size.
|
||||
/// </summary>
|
||||
private int _count;
|
||||
|
||||
/// <summary>
|
||||
/// The _start. Index of the first element in buffer.
|
||||
/// </summary>
|
||||
private int _start;
|
||||
|
||||
public CircularBuffer(int capacity)
|
||||
: this(capacity, new T[] {}) {}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CircularBuffer{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name='capacity'>
|
||||
/// Buffer capacity. Must be positive.
|
||||
/// </param>
|
||||
/// <param name='items'>
|
||||
/// Items to fill buffer with. Items length must be less than capacity.
|
||||
/// Sugestion: use Skip(x).Take(y).ToArray() to build this argument from
|
||||
/// any enumerable.
|
||||
/// </param>
|
||||
public CircularBuffer(int capacity, T[] items)
|
||||
{
|
||||
if (capacity < 1)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Circular buffer cannot have negative or zero capacity.", "capacity");
|
||||
}
|
||||
if (items == null)
|
||||
{
|
||||
throw new ArgumentNullException("items");
|
||||
}
|
||||
if (items.Length > capacity)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Too many items to fit circular buffer", "items");
|
||||
}
|
||||
|
||||
_buffer = new T[capacity];
|
||||
|
||||
Array.Copy(items, _buffer, items.Length);
|
||||
_count = items.Length;
|
||||
|
||||
_start = 0;
|
||||
_end = _count == capacity ? 0 : _count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum capacity of the buffer. Elements pushed into the buffer after
|
||||
/// maximum capacity is reached (IsFull = true), will remove an element.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get { return _buffer.Length; }
|
||||
}
|
||||
|
||||
public bool IsFull
|
||||
{
|
||||
get { return Count == Capacity; }
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return Count == 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current buffer size (the number of elements that the buffer has).
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get { return _count; }
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsEmpty)
|
||||
{
|
||||
throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer is empty", index));
|
||||
}
|
||||
if (index >= _count)
|
||||
{
|
||||
throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}",
|
||||
index, _count));
|
||||
}
|
||||
var actualIndex = InternalIndex(index);
|
||||
return _buffer[actualIndex];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IsEmpty)
|
||||
{
|
||||
throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer is empty", index));
|
||||
}
|
||||
if (index >= _count)
|
||||
{
|
||||
throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}",
|
||||
index, _count));
|
||||
}
|
||||
var actualIndex = InternalIndex(index);
|
||||
_buffer[actualIndex] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_count = 0;
|
||||
_start = 0;
|
||||
_end = 0;
|
||||
}
|
||||
|
||||
#region IEnumerable<T> implementation
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
var segments = new ArraySegment<T>[2] {ArrayOne(), ArrayTwo()};
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
for (var i = 0; i < segment.Count; i++)
|
||||
{
|
||||
yield return segment.Array[segment.Offset + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable implementation
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IList<T> implementation
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Element at the front of the buffer - this[0].
|
||||
/// </summary>
|
||||
/// <returns>The value of the element of type T at the front of the buffer.</returns>
|
||||
public T Front()
|
||||
{
|
||||
ThrowIfEmpty();
|
||||
return _buffer[_start];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Element at the back of the buffer - this[Size - 1].
|
||||
/// </summary>
|
||||
/// <returns>The value of the element of type T at the back of the buffer.</returns>
|
||||
public T Back()
|
||||
{
|
||||
ThrowIfEmpty();
|
||||
return _buffer[(_end != 0 ? _end : _count) - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a new element to the back of the buffer. Back()/this[Size-1]
|
||||
/// will now return this element.
|
||||
/// When the buffer is full, the element at Front()/this[0] will be
|
||||
/// popped to allow for this new element to fit.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to push to the back of the buffer</param>
|
||||
public void PushBack(T item)
|
||||
{
|
||||
if (IsFull)
|
||||
{
|
||||
_buffer[_end] = item;
|
||||
Increment(ref _end);
|
||||
_start = _end;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer[_end] = item;
|
||||
Increment(ref _end);
|
||||
++_count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a new element to the front of the buffer. Front()/this[0]
|
||||
/// will now return this element.
|
||||
/// When the buffer is full, the element at Back()/this[Size-1] will be
|
||||
/// popped to allow for this new element to fit.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to push to the front of the buffer</param>
|
||||
public void PushFront(T item)
|
||||
{
|
||||
if (IsFull)
|
||||
{
|
||||
Decrement(ref _start);
|
||||
_end = _start;
|
||||
_buffer[_start] = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
Decrement(ref _start);
|
||||
_buffer[_start] = item;
|
||||
++_count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the element at the back of the buffer. Decreassing the
|
||||
/// Buffer size by 1.
|
||||
/// </summary>
|
||||
public void PopBack()
|
||||
{
|
||||
ThrowIfEmpty("Cannot take elements from an empty buffer.");
|
||||
Decrement(ref _end);
|
||||
_buffer[_end] = default(T);
|
||||
--_count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the element at the front of the buffer. Decreassing the
|
||||
/// Buffer size by 1.
|
||||
/// </summary>
|
||||
public void PopFront()
|
||||
{
|
||||
ThrowIfEmpty("Cannot take elements from an empty buffer.");
|
||||
_buffer[_start] = default(T);
|
||||
Increment(ref _start);
|
||||
--_count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the buffer contents to an array, acording to the logical
|
||||
/// contents of the buffer (i.e. independent of the internal
|
||||
/// order/contents)
|
||||
/// </summary>
|
||||
/// <returns>A new array with a copy of the buffer contents.</returns>
|
||||
public T[] ToArray()
|
||||
{
|
||||
var newArray = new T[Count];
|
||||
var newArrayOffset = 0;
|
||||
var segments = new ArraySegment<T>[2] {ArrayOne(), ArrayTwo()};
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
Array.Copy(segment.Array, segment.Offset, newArray, newArrayOffset, segment.Count);
|
||||
newArrayOffset += segment.Count;
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
|
||||
{
|
||||
if (IsEmpty)
|
||||
{
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the provided index variable by one, wrapping
|
||||
/// around if necessary.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
private void Increment(ref int index)
|
||||
{
|
||||
if (++index == Capacity)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrements the provided index variable by one, wrapping
|
||||
/// around if necessary.
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
private void Decrement(ref int index)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
index = Capacity;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the index in the argument to an index in <code>_buffer</code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The transformed index.
|
||||
/// </returns>
|
||||
/// <param name='index'>
|
||||
/// External index.
|
||||
/// </param>
|
||||
private int InternalIndex(int index)
|
||||
{
|
||||
return _start + (index < (Capacity - _start) ? index : index - Capacity);
|
||||
}
|
||||
|
||||
// doing ArrayOne and ArrayTwo methods returning ArraySegment<T> as seen here:
|
||||
// http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1957cccdcb0c4ef7d80a34a990065818d
|
||||
// http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1f5081a54afbc2dfc1a7fb20329df7d5b
|
||||
// should help a lot with the code.
|
||||
|
||||
#region Array items easy access.
|
||||
|
||||
// The array is composed by at most two non-contiguous segments,
|
||||
// the next two methods allow easy access to those.
|
||||
|
||||
private ArraySegment<T> ArrayOne()
|
||||
{
|
||||
if (_start <= _end)
|
||||
{
|
||||
return new ArraySegment<T>(_buffer, _start, _end - _start);
|
||||
}
|
||||
return new ArraySegment<T>(_buffer, _start, _buffer.Length - _start);
|
||||
}
|
||||
|
||||
private ArraySegment<T> ArrayTwo()
|
||||
{
|
||||
if (_start < _end)
|
||||
{
|
||||
return new ArraySegment<T>(_buffer, _end, 0);
|
||||
}
|
||||
return new ArraySegment<T>(_buffer, 0, _end);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39fd981a95abcb647a9c6ecd52007e71
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
* This file has been deleted.
|
||||
* This empty file is left here to ensure it is properly overwritten when importing a new version of the package over an old version.
|
||||
*/
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f809cd2d9d5ae074cbecca0ab4d472b6
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using SRF;
|
||||
using SRF.Service;
|
||||
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// The default bug report handler - this submits to the SRDebugger API using the API key configured in the SRDebugger
|
||||
/// settings window.
|
||||
/// </summary>
|
||||
internal class InternalBugReporterHandler : IBugReporterHandler
|
||||
{
|
||||
public bool IsUsable
|
||||
{
|
||||
get { return Settings.Instance.EnableBugReporter && !string.IsNullOrWhiteSpace(Settings.Instance.ApiKey); }
|
||||
}
|
||||
|
||||
public void Submit(BugReport report, Action<BugReportSubmitResult> onComplete, IProgress<float> progress)
|
||||
{
|
||||
BugReportApi.Submit(report, Settings.Instance.ApiKey, onComplete, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f424b0a8b303d9843b15a6bf70ebf4ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SRF.Service;
|
||||
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Workaround for the debug panel not being initialized on startup.
|
||||
/// SROptions needs to register itself but not cause auto-initialization.
|
||||
/// This class buffers requests to register contains until there is a handler in place to deal with them.
|
||||
/// Once the handler is in place, all buffered requests are passed in and future requests invoke the handler directly.
|
||||
/// </summary>
|
||||
[Service(typeof(InternalOptionsRegistry))]
|
||||
public sealed class InternalOptionsRegistry
|
||||
{
|
||||
private List<object> _registeredContainers = new List<object>();
|
||||
private Action<object> _handler;
|
||||
|
||||
public void AddOptionContainer(object obj)
|
||||
{
|
||||
if (_handler != null)
|
||||
{
|
||||
_handler(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
_registeredContainers.Add(obj);
|
||||
}
|
||||
|
||||
public void SetHandler(Action<object> action)
|
||||
{
|
||||
_handler = action;
|
||||
|
||||
foreach (object o in _registeredContainers)
|
||||
{
|
||||
_handler(o);
|
||||
}
|
||||
|
||||
_registeredContainers = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12f482545d1833a4e823d79898cb46ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,174 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SRF;
|
||||
using UI.Controls;
|
||||
using UI.Controls.Data;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
public static class OptionControlFactory
|
||||
{
|
||||
private static IList<DataBoundControl> _dataControlPrefabs;
|
||||
private static ActionControl _actionControlPrefab;
|
||||
|
||||
private static readonly Dictionary<OptionType, DataBoundControl> TypeCache = new Dictionary<OptionType, DataBoundControl>();
|
||||
|
||||
public static bool CanCreateControl(OptionDefinition from)
|
||||
{
|
||||
PopulateDataControlPrefabs();
|
||||
if (from.Property != null)
|
||||
{
|
||||
return TryGetDataControlPrefab(from) != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _actionControlPrefab != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a control from an <c>OptionDefinition</c>, optionally providing <paramref name="categoryPrefix" /> to remove
|
||||
/// the category name from the start of the control.
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="categoryPrefix"></param>
|
||||
/// <returns></returns>
|
||||
public static OptionsControlBase CreateControl(OptionDefinition from, string categoryPrefix = null)
|
||||
{
|
||||
PopulateDataControlPrefabs();
|
||||
|
||||
if (from.Property != null)
|
||||
{
|
||||
return CreateDataControl(from, categoryPrefix);
|
||||
}
|
||||
|
||||
if (from.Method != null)
|
||||
{
|
||||
return CreateActionControl(from, categoryPrefix);
|
||||
}
|
||||
|
||||
throw new Exception("OptionDefinition did not contain property or method.");
|
||||
}
|
||||
|
||||
private static void PopulateDataControlPrefabs()
|
||||
{
|
||||
if (_dataControlPrefabs == null)
|
||||
{
|
||||
_dataControlPrefabs = Resources.LoadAll<DataBoundControl>(SRDebugPaths.DataControlsResourcesPath);
|
||||
}
|
||||
|
||||
if (_actionControlPrefab == null)
|
||||
{
|
||||
_actionControlPrefab =
|
||||
Resources.LoadAll<ActionControl>(SRDebugPaths.DataControlsResourcesPath).FirstOrDefault();
|
||||
}
|
||||
|
||||
if (_actionControlPrefab == null)
|
||||
{
|
||||
Debug.LogError("[SRDebugger.Options] Cannot find ActionControl prefab.");
|
||||
}
|
||||
}
|
||||
|
||||
private static ActionControl CreateActionControl(OptionDefinition from, string categoryPrefix = null)
|
||||
{
|
||||
var control = SRInstantiate.Instantiate(_actionControlPrefab);
|
||||
|
||||
if (control == null)
|
||||
{
|
||||
Debug.LogWarning("[SRDebugger.OptionsTab] Error creating action control from prefab");
|
||||
return null;
|
||||
}
|
||||
|
||||
control.SetMethod(from.Name, from.Method);
|
||||
control.Option = from;
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
private static DataBoundControl CreateDataControl(OptionDefinition from, string categoryPrefix = null)
|
||||
{
|
||||
var prefab = TryGetDataControlPrefab(from);
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogWarning(
|
||||
"[SRDebugger.OptionsTab] Can't find data control for type {0}".Fmt(from.Property.PropertyType));
|
||||
return null;
|
||||
}
|
||||
|
||||
var instance = SRInstantiate.Instantiate(prefab);
|
||||
|
||||
try
|
||||
{
|
||||
var n = from.Name;
|
||||
|
||||
// Remove category name from the start of the property name
|
||||
if (!string.IsNullOrEmpty(categoryPrefix) && n.StartsWith(categoryPrefix))
|
||||
{
|
||||
n = n.Substring(categoryPrefix.Length);
|
||||
}
|
||||
|
||||
instance.Bind(n, from.Property);
|
||||
instance.Option = from;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("[SRDebugger.Options] Error binding to property {0}".Fmt(from.Name));
|
||||
Debug.LogException(e);
|
||||
|
||||
Object.Destroy(instance);
|
||||
instance = null;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static DataBoundControl TryGetDataControlPrefab(OptionDefinition from)
|
||||
{
|
||||
OptionType type = new OptionType(@from.Property.PropertyType, !@from.Property.CanWrite);
|
||||
|
||||
DataBoundControl control;
|
||||
if (!TypeCache.TryGetValue(type, out control))
|
||||
{
|
||||
control = _dataControlPrefabs.FirstOrDefault(p =>
|
||||
p.CanBind(@from.Property.PropertyType, !@from.Property.CanWrite));
|
||||
TypeCache.Add(type, control);
|
||||
}
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
private struct OptionType
|
||||
{
|
||||
public readonly Type Type;
|
||||
public readonly bool IsReadyOnly;
|
||||
|
||||
public OptionType(Type type, bool isReadyOnly)
|
||||
{
|
||||
Type = type;
|
||||
IsReadyOnly = isReadyOnly;
|
||||
}
|
||||
|
||||
public bool Equals(OptionType other)
|
||||
{
|
||||
return Equals(Type, other.Type) && IsReadyOnly == other.IsReadyOnly;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is OptionType other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((Type != null ? Type.GetHashCode() : 0) * 397) ^ IsReadyOnly.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d6e807b7446052409d51e03ab38cfae
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using SRF.Helpers;
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
/// <summary>
|
||||
/// Class describing how an option should be presented within the options panel.
|
||||
/// </summary>
|
||||
public sealed class OptionDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Display-name for the option.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The category that this option should be placed within.
|
||||
/// </summary>
|
||||
public string Category { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sort order within the category. Order is low to high, (options with lower SortPriority will appear before
|
||||
/// options with higher SortPriority).
|
||||
/// </summary>
|
||||
public int SortPriority { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this option is a method that should be invoked.
|
||||
/// </summary>
|
||||
public bool IsMethod
|
||||
{
|
||||
get { return Method != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this option is a property that has a value.
|
||||
/// </summary>
|
||||
public bool IsProperty
|
||||
{
|
||||
get { return Property != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The underlying method for this OptionDefinition.
|
||||
/// Can be null if <see cref="IsMethod"/> is false.
|
||||
/// </summary>
|
||||
public SRF.Helpers.MethodReference Method { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The underlying property for this OptionDefinition.
|
||||
/// Can be null if <see cref="IsProperty"/> is false.
|
||||
/// </summary>
|
||||
public SRF.Helpers.PropertyReference Property { get; private set; }
|
||||
|
||||
private OptionDefinition(string name, string category, int sortPriority)
|
||||
{
|
||||
Name = name;
|
||||
Category = category;
|
||||
SortPriority = sortPriority;
|
||||
}
|
||||
|
||||
public OptionDefinition(string name, string category, int sortPriority, SRF.Helpers.MethodReference method)
|
||||
: this(name, category, sortPriority)
|
||||
{
|
||||
Method = method;
|
||||
}
|
||||
|
||||
public OptionDefinition(string name, string category, int sortPriority, SRF.Helpers.PropertyReference property)
|
||||
: this(name, category, sortPriority)
|
||||
{
|
||||
Property = property;
|
||||
}
|
||||
|
||||
public static OptionDefinition FromMethod(string name, Action callback, string category = "Default", int sortPriority = 0)
|
||||
{
|
||||
return new OptionDefinition(name, category, sortPriority, callback);;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an option definition from a setter and getter lambda.
|
||||
/// </summary>
|
||||
/// <param name="name">Name to display in options menu.</param>
|
||||
/// <param name="getter">Method to get the current value of the property.</param>
|
||||
/// <param name="setter">Method to set the value of the property (can be null if read-only)</param>
|
||||
/// <param name="category">Category to display the option in.</param>
|
||||
/// <param name="sortPriority">Sort priority to arrange the option within the category.</param>
|
||||
/// <returns>The created option definition.</returns>
|
||||
public static OptionDefinition Create<T>(string name, Func<T> getter, Action<T> setter = null, string category = "Default", int sortPriority = 0)
|
||||
{
|
||||
return new OptionDefinition(name, category, sortPriority, PropertyReference.FromLambda(getter, setter));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6fb9bd71eceb4145a013bb7fe025c01
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
14
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Paths.cs
Normal file
14
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Paths.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
public static class SRDebugPaths
|
||||
{
|
||||
public const string DataControlsResourcesPath = "SRDebugger/UI/Prefabs/Options";
|
||||
public const string TriggerPrefabPath = "SRDebugger/UI/Prefabs/Trigger";
|
||||
public const string DebugPanelPrefabPath = "SRDebugger/UI/Prefabs/DebugPanel";
|
||||
public const string PinnedUIPrefabPath = "SRDebugger/UI/Prefabs/PinnedUI";
|
||||
public const string DockConsolePrefabPath = "SRDebugger/UI/Prefabs/DockConsole";
|
||||
public const string PinEntryPrefabPath = "SRDebugger/UI/Prefabs/PinEntry";
|
||||
public const string BugReportPopoverPath = "SRDebugger/UI/Prefabs/BugReportPopover";
|
||||
public const string BugReportSheetPath = "SRDebugger/UI/Prefabs/BugReportSheet";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 487af04ceed59b6409168c2d466c2f73
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,73 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Scripts.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Behaviour that supports SRDebugger reloading itself after a script recompile is detected.
|
||||
/// </summary>
|
||||
public class SRScriptRecompileHelper : MonoBehaviour
|
||||
{
|
||||
private static SRScriptRecompileHelper _instance;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
public static void Initialize()
|
||||
{
|
||||
if (_instance != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var go = new GameObject("SRDebugger Script Recompile Helper (Editor Only)");
|
||||
DontDestroyOnLoad(go);
|
||||
go.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy;
|
||||
go.AddComponent<SRScriptRecompileHelper>();
|
||||
}
|
||||
|
||||
private bool _hasEnabled;
|
||||
private bool _srdebuggerHasInitialized;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if(_instance != null)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
_instance = this;
|
||||
|
||||
// Don't take any action on the first OnEnable()
|
||||
if (!_hasEnabled)
|
||||
{
|
||||
_hasEnabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Next OnEnable() will be due to script reload.
|
||||
AutoInitialize.OnLoadBeforeScene();
|
||||
|
||||
if (_srdebuggerHasInitialized)
|
||||
{
|
||||
Debug.Log("[SRScriptRecompileHelper] Restoring SRDebugger after script reload.", this);
|
||||
SRDebug.Init();
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
// Destroy this object when leaving play mode (otherwise it will linger and a new instance will be created next time play mode is entered).
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
public static void SetHasInitialized()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
_instance._srdebuggerHasInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cb2b7903b1672544b02d628ac0c1dfd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 24000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
122
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Service.cs
Normal file
122
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Service.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
using Services;
|
||||
using SRF.Service;
|
||||
|
||||
public static class Service
|
||||
{
|
||||
private static IConsoleService _consoleService;
|
||||
private static IDebugPanelService _debugPanelService;
|
||||
private static IDebugTriggerService _debugTriggerService;
|
||||
private static IPinnedUIService _pinnedUiService;
|
||||
private static IDebugCameraService _debugCameraService;
|
||||
private static IOptionsService _optionsService;
|
||||
private static IDockConsoleService _dockConsoleService;
|
||||
|
||||
#if UNITY_EDITOR && ((!UNITY_2017 && !UNITY_2018 && !UNITY_2019) || UNITY_2019_3_OR_NEWER)
|
||||
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
public static void RuntimeInitialize()
|
||||
{
|
||||
// Clear service references at startup in case of "enter play mode without domain reload"
|
||||
_consoleService = null;
|
||||
_debugPanelService = null;
|
||||
_debugTriggerService = null;
|
||||
_pinnedUiService = null;
|
||||
_debugCameraService = null;
|
||||
_optionsService = null;
|
||||
_dockConsoleService = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static IConsoleService Console
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_consoleService == null)
|
||||
{
|
||||
_consoleService = SRServiceManager.GetService<IConsoleService>();
|
||||
}
|
||||
|
||||
return _consoleService;
|
||||
}
|
||||
}
|
||||
|
||||
public static IDockConsoleService DockConsole
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dockConsoleService == null)
|
||||
{
|
||||
_dockConsoleService = SRServiceManager.GetService<IDockConsoleService>();
|
||||
}
|
||||
|
||||
return _dockConsoleService;
|
||||
}
|
||||
}
|
||||
|
||||
public static IDebugPanelService Panel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_debugPanelService == null)
|
||||
{
|
||||
_debugPanelService = SRServiceManager.GetService<IDebugPanelService>();
|
||||
}
|
||||
|
||||
return _debugPanelService;
|
||||
}
|
||||
}
|
||||
|
||||
public static IDebugTriggerService Trigger
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_debugTriggerService == null)
|
||||
{
|
||||
_debugTriggerService = SRServiceManager.GetService<IDebugTriggerService>();
|
||||
}
|
||||
|
||||
return _debugTriggerService;
|
||||
}
|
||||
}
|
||||
|
||||
public static IPinnedUIService PinnedUI
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pinnedUiService == null)
|
||||
{
|
||||
_pinnedUiService = SRServiceManager.GetService<IPinnedUIService>();
|
||||
}
|
||||
|
||||
return _pinnedUiService;
|
||||
}
|
||||
}
|
||||
|
||||
public static IDebugCameraService DebugCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_debugCameraService == null)
|
||||
{
|
||||
_debugCameraService = SRServiceManager.GetService<IDebugCameraService>();
|
||||
}
|
||||
|
||||
return _debugCameraService;
|
||||
}
|
||||
}
|
||||
|
||||
public static IOptionsService Options
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_optionsService == null)
|
||||
{
|
||||
_optionsService = SRServiceManager.GetService<IOptionsService>();
|
||||
}
|
||||
|
||||
return _optionsService;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe213cfca7e22e844abfd16c258dd08e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
public class SRDebugStrings
|
||||
{
|
||||
public static readonly SRDebugStrings Current = new SRDebugStrings();
|
||||
public readonly string Console_MessageTruncated = "-- Message Truncated --";
|
||||
public readonly string Console_NoStackTrace = "-- No Stack Trace Available --";
|
||||
public readonly string PinEntryPrompt = "Enter code to open debug panel";
|
||||
|
||||
public readonly string Profiler_DisableProfilerInfo =
|
||||
"Unity profiler is currently <b>enabled</b>. Disable to improve performance.";
|
||||
|
||||
public readonly string Profiler_EnableProfilerInfo =
|
||||
"Unity profiler is currently <b>disabled</b>. Enable to show more information.";
|
||||
|
||||
public readonly string Profiler_NoProInfo =
|
||||
"Unity profiler is currently <b>disabled</b>. Unity Pro is required to enable it.";
|
||||
|
||||
public readonly string Profiler_NotSupported = "Unity profiler is <b>not supported</b> in this build.";
|
||||
|
||||
public readonly string ProfilerCameraListenerHelp =
|
||||
"This behaviour is attached by the SRDebugger profiler to calculate render times.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34bc872e688c2eb4ca1794728e6ff4fd
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
233
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Util.cs
Normal file
233
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Internal/Util.cs
Normal file
@@ -0,0 +1,233 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SRDebugger.Internal
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using SRF.Helpers;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
public static class SRDebuggerUtil
|
||||
{
|
||||
public static bool IsMobilePlatform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Application.isMobilePlatform)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (Application.platform)
|
||||
{
|
||||
#if UNITY_5 || UNITY_5_3_OR_NEWER
|
||||
case RuntimePlatform.WSAPlayerARM:
|
||||
case RuntimePlatform.WSAPlayerX64:
|
||||
case RuntimePlatform.WSAPlayerX86:
|
||||
#else
|
||||
case RuntimePlatform.MetroPlayerARM:
|
||||
case RuntimePlatform.MetroPlayerX64:
|
||||
case RuntimePlatform.MetroPlayerX86:
|
||||
#endif
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If no event system exists, create one
|
||||
/// </summary>
|
||||
/// <returns>True if the event system was created as a result of this call</returns>
|
||||
public static bool EnsureEventSystemExists()
|
||||
{
|
||||
if (!Settings.Instance.EnableEventSystemGeneration)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EventSystem.current != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var e = Object.FindObjectOfType<EventSystem>();
|
||||
|
||||
// Check if EventSystem is in the scene but not registered yet
|
||||
if (e != null && e.gameObject.activeSelf && e.enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug.LogWarning("[SRDebugger] No EventSystem found in scene - creating a default one. Disable this behaviour in Window -> SRDebugger -> Settings Window -> Advanced)");
|
||||
|
||||
CreateDefaultEventSystem();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void CreateDefaultEventSystem()
|
||||
{
|
||||
var go = new GameObject("EventSystem (Created by SRDebugger, disable in Window -> SRDebugger -> Settings Window -> Advanced)");
|
||||
go.AddComponent<EventSystem>();
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM && ENABLE_LEGACY_INPUT_MANAGER
|
||||
switch (Settings.Instance.UIInputMode)
|
||||
{
|
||||
case Settings.UIModes.NewInputSystem:
|
||||
AddInputSystem(go);
|
||||
Debug.LogWarning("[SRDebugger] Automatically generated EventSystem is using Unity Input System (can be changed to use Legacy Input in Window -> SRDebugger -> Settings Window -> Advanced)");
|
||||
break;
|
||||
case Settings.UIModes.LegacyInputSystem:
|
||||
AddLegacyInputSystem(go);
|
||||
Debug.LogWarning("[SRDebugger] Automatically generated EventSystem is using Legacy Input (can be changed to use Unity Input System in Window -> SRDebugger -> Settings Window -> Advanced)");
|
||||
break;
|
||||
}
|
||||
#elif ENABLE_INPUT_SYSTEM
|
||||
AddInputSystem(go);
|
||||
#elif ENABLE_LEGACY_INPUT_MANAGER || (!ENABLE_INPUT_SYSTEM && !UNITY_2019_3_OR_NEWER)
|
||||
AddLegacyInputSystem(go);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
private static void AddInputSystem(GameObject go)
|
||||
{
|
||||
go.AddComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>();
|
||||
|
||||
// Disable/re-enable to force some initialization.
|
||||
// fix for input not being recognized until component is toggled off then on
|
||||
go.SetActive(false);
|
||||
go.SetActive(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_LEGACY_INPUT_MANAGER || (!ENABLE_INPUT_SYSTEM && !UNITY_2019_3_OR_NEWER)
|
||||
private static void AddLegacyInputSystem(GameObject go)
|
||||
{
|
||||
go.AddComponent<StandaloneInputModule>();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Scan <paramref name="obj" /> for valid options and return a collection of them.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static List<OptionDefinition> ScanForOptions(object obj)
|
||||
{
|
||||
var options = new List<OptionDefinition>();
|
||||
|
||||
#if NETFX_CORE
|
||||
var members = obj.GetType().GetTypeInfo().DeclaredMembers;
|
||||
#else
|
||||
|
||||
var members =
|
||||
obj.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty |
|
||||
BindingFlags.SetProperty | BindingFlags.InvokeMethod);
|
||||
|
||||
#endif
|
||||
|
||||
var ignoreAssembly = typeof(MonoBehaviour).Assembly;
|
||||
|
||||
foreach (var memberInfo in members)
|
||||
{
|
||||
// Skip any properties that are from built-in Unity types (e.g. Behaviour, MonoBehaviour)
|
||||
if (memberInfo.DeclaringType != null && memberInfo.DeclaringType.Assembly == ignoreAssembly)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var browsable = memberInfo.GetCustomAttribute<BrowsableAttribute>();
|
||||
if (browsable != null)
|
||||
{
|
||||
if (!browsable.Browsable)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find user-specified category name from attribute
|
||||
var categoryAttribute = SRReflection.GetAttribute<CategoryAttribute>(memberInfo);
|
||||
var category = categoryAttribute == null ? "Default" : categoryAttribute.Category;
|
||||
|
||||
// Find user-specified sorting priority from attribute
|
||||
var sortAttribute = SRReflection.GetAttribute<SortAttribute>(memberInfo);
|
||||
var sortPriority = sortAttribute == null ? 0 : sortAttribute.SortPriority;
|
||||
|
||||
// Find user-specified display name from attribute
|
||||
var nameAttribute = SRReflection.GetAttribute<DisplayNameAttribute>(memberInfo);
|
||||
var name = nameAttribute == null ? memberInfo.Name : nameAttribute.DisplayName;
|
||||
|
||||
if (memberInfo is PropertyInfo)
|
||||
{
|
||||
var propertyInfo = memberInfo as PropertyInfo;
|
||||
|
||||
// Only allow properties with public read/write
|
||||
#if NETFX_CORE
|
||||
if(propertyInfo.GetMethod == null)
|
||||
continue;
|
||||
|
||||
// Ignore static members
|
||||
if (propertyInfo.GetMethod.IsStatic)
|
||||
continue;
|
||||
#else
|
||||
if (propertyInfo.GetGetMethod() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore static members
|
||||
if ((propertyInfo.GetGetMethod().Attributes & MethodAttributes.Static) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
options.Add(new OptionDefinition(name, category, sortPriority,
|
||||
new SRF.Helpers.PropertyReference(obj, propertyInfo)));
|
||||
}
|
||||
else if (memberInfo is MethodInfo)
|
||||
{
|
||||
var methodInfo = memberInfo as MethodInfo;
|
||||
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip methods with parameters or non-void return type
|
||||
if (methodInfo.ReturnType != typeof (void) || methodInfo.GetParameters().Length > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
options.Add(new OptionDefinition(name, category, sortPriority,
|
||||
new SRF.Helpers.MethodReference(obj, methodInfo)));
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
public static string GetNumberString(int value, int max, string exceedsMaxString)
|
||||
{
|
||||
if (value >= max)
|
||||
{
|
||||
return exceedsMaxString;
|
||||
}
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public static void ConfigureCanvas(Canvas canvas)
|
||||
{
|
||||
if (Settings.Instance.UseDebugCamera)
|
||||
{
|
||||
canvas.worldCamera = Service.DebugCamera.Camera;
|
||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e0f09d4b116f524381461f865525607
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Profiler.meta
Normal file
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Profiler.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bca87b44250eab3469ec77e0848afc2e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
* This file has been deleted.
|
||||
* This empty file is left here to ensure it is properly overwritten when importing a new version of the package over an old version.
|
||||
*/
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3172283e0204f3e47968b9f791c5a2df
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace SRDebugger.Profiler
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The profiler has a separate monobehaviour to listen for LateUpdate, and is placed
|
||||
/// at the end of the script execution order.
|
||||
/// </summary>
|
||||
public class ProfilerLateUpdateListener : MonoBehaviour
|
||||
{
|
||||
public Action OnLateUpdate;
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (OnLateUpdate != null)
|
||||
{
|
||||
OnLateUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21048b348f7dc284ab97209ec32253c4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 32001
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,128 @@
|
||||
namespace SRDebugger.Profiler
|
||||
{
|
||||
using System.Diagnostics;
|
||||
using Services;
|
||||
using SRF;
|
||||
using SRF.Service;
|
||||
using UnityEngine;
|
||||
|
||||
public class ProfilerServiceImpl : SRServiceBase<IProfilerService>, IProfilerService
|
||||
{
|
||||
public float AverageFrameTime { get; private set; }
|
||||
public float LastFrameTime { get; private set; }
|
||||
|
||||
public CircularBuffer<ProfilerFrame> FrameBuffer
|
||||
{
|
||||
get { return _frameBuffer; }
|
||||
}
|
||||
|
||||
private const int FrameBufferSize = 400;
|
||||
|
||||
private readonly CircularBuffer<ProfilerFrame>
|
||||
_frameBuffer = new CircularBuffer<ProfilerFrame>(FrameBufferSize);
|
||||
|
||||
private ProfilerLateUpdateListener _lateUpdateListener;
|
||||
|
||||
private readonly Stopwatch _stopwatch = new Stopwatch();
|
||||
|
||||
// Time between first Update() and last LateUpdate().
|
||||
private double _updateDuration;
|
||||
|
||||
// Time that first camera rendered.
|
||||
private double _renderStartTime;
|
||||
|
||||
// Time between first camera prerender and last camera postrender.
|
||||
private double _renderDuration;
|
||||
|
||||
private int _camerasThisFrame;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_lateUpdateListener = gameObject.AddComponent<ProfilerLateUpdateListener>();
|
||||
_lateUpdateListener.OnLateUpdate = OnLateUpdate;
|
||||
|
||||
CachedGameObject.hideFlags = HideFlags.NotEditable;
|
||||
CachedTransform.SetParent(Hierarchy.Get("SRDebugger"), true);
|
||||
|
||||
Camera.onPreRender += OnCameraPreRender;
|
||||
Camera.onPostRender += OnCameraPostRender;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
_camerasThisFrame = 0;
|
||||
|
||||
EndFrame();
|
||||
|
||||
// Set the frame time for the last frame
|
||||
if (FrameBuffer.Count > 0)
|
||||
{
|
||||
var frame = FrameBuffer.Back();
|
||||
frame.FrameTime = Time.unscaledDeltaTime;
|
||||
FrameBuffer[FrameBuffer.Count - 1] = frame;
|
||||
}
|
||||
|
||||
LastFrameTime = Time.unscaledDeltaTime;
|
||||
|
||||
var frameCount = Mathf.Min(20, FrameBuffer.Count);
|
||||
|
||||
var f = 0d;
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
{
|
||||
f += FrameBuffer[FrameBuffer.Count - 1 - i].FrameTime;
|
||||
}
|
||||
|
||||
AverageFrameTime = (float) f / frameCount;
|
||||
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
protected void PushFrame(double totalTime, double updateTime, double renderTime)
|
||||
{
|
||||
//UnityEngine.Debug.Log("Frame: u: {0} r: {1}".Fmt(updateTime, renderTime));
|
||||
|
||||
_frameBuffer.PushBack(new ProfilerFrame
|
||||
{
|
||||
OtherTime = totalTime - updateTime - renderTime,
|
||||
UpdateTime = updateTime,
|
||||
RenderTime = renderTime
|
||||
});
|
||||
}
|
||||
|
||||
private void OnLateUpdate()
|
||||
{
|
||||
_updateDuration = _stopwatch.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
private void OnCameraPreRender(Camera cam)
|
||||
{
|
||||
if (_camerasThisFrame == 0)
|
||||
{
|
||||
_renderStartTime = _stopwatch.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
_camerasThisFrame++;
|
||||
}
|
||||
|
||||
private void OnCameraPostRender(Camera cam)
|
||||
{
|
||||
_renderDuration = _stopwatch.Elapsed.TotalSeconds - _renderStartTime;
|
||||
}
|
||||
|
||||
private void EndFrame()
|
||||
{
|
||||
if (_stopwatch.IsRunning)
|
||||
{
|
||||
PushFrame(_stopwatch.Elapsed.TotalSeconds, _updateDuration, _renderDuration);
|
||||
|
||||
_stopwatch.Reset();
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
_updateDuration = _renderDuration = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff0319556f3fbc341b877ff4b1ff94ba
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -32000
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,139 @@
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
|
||||
namespace SRDebugger.Profiler
|
||||
{
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using SRDebugger.Services;
|
||||
using SRF;
|
||||
using SRF.Service;
|
||||
using UnityEngine;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
using UnityEngine.Rendering;
|
||||
#else
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
#endif
|
||||
|
||||
public class SRPProfilerService : SRServiceBase<IProfilerService>, IProfilerService
|
||||
{
|
||||
public float AverageFrameTime { get; private set; }
|
||||
public float LastFrameTime { get; private set; }
|
||||
|
||||
public CircularBuffer<ProfilerFrame> FrameBuffer
|
||||
{
|
||||
get { return _frameBuffer; }
|
||||
}
|
||||
|
||||
private const int FrameBufferSize = 400;
|
||||
private readonly CircularBuffer<ProfilerFrame> _frameBuffer = new CircularBuffer<ProfilerFrame>(FrameBufferSize);
|
||||
|
||||
private ProfilerLateUpdateListener _lateUpdateListener;
|
||||
|
||||
// Time between first Update() and last LateUpdate()
|
||||
private double _updateDuration;
|
||||
|
||||
// Time that render pipeline starts
|
||||
private double _renderStartTime;
|
||||
|
||||
// Time between scripted render pipeline starts + EndOfFrame
|
||||
private double _renderDuration;
|
||||
|
||||
private readonly Stopwatch _stopwatch = new Stopwatch();
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
_lateUpdateListener = gameObject.AddComponent<ProfilerLateUpdateListener>();
|
||||
_lateUpdateListener.OnLateUpdate = OnLateUpdate;
|
||||
|
||||
CachedGameObject.hideFlags = HideFlags.NotEditable;
|
||||
CachedTransform.SetParent(Hierarchy.Get("SRDebugger"), true);
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
RenderPipelineManager.beginFrameRendering += RenderPipelineOnBeginFrameRendering;
|
||||
#else
|
||||
RenderPipeline.beginFrameRendering += RenderPipelineOnBeginFrameRendering;
|
||||
#endif
|
||||
|
||||
StartCoroutine(EndOfFrameCoroutine());
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
EndFrame();
|
||||
|
||||
// Set the frame time for the last frame
|
||||
if (FrameBuffer.Count > 0)
|
||||
{
|
||||
var frame = FrameBuffer.Back();
|
||||
frame.FrameTime = Time.unscaledDeltaTime;
|
||||
FrameBuffer[FrameBuffer.Count - 1] = frame;
|
||||
}
|
||||
|
||||
LastFrameTime = Time.unscaledDeltaTime;
|
||||
|
||||
var frameCount = Mathf.Min(20, FrameBuffer.Count);
|
||||
|
||||
var f = 0d;
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
{
|
||||
f += FrameBuffer[FrameBuffer.Count - 1 - i].FrameTime;
|
||||
}
|
||||
|
||||
AverageFrameTime = (float)f / frameCount;
|
||||
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
IEnumerator EndOfFrameCoroutine()
|
||||
{
|
||||
var endOfFrame = new WaitForEndOfFrame();
|
||||
|
||||
while (true)
|
||||
{
|
||||
yield return endOfFrame;
|
||||
_renderDuration = _stopwatch.Elapsed.TotalSeconds - _renderStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
protected void PushFrame(double totalTime, double updateTime, double renderTime)
|
||||
{
|
||||
_frameBuffer.PushBack(new ProfilerFrame
|
||||
{
|
||||
OtherTime = totalTime - updateTime - renderTime,
|
||||
UpdateTime = updateTime,
|
||||
RenderTime = renderTime
|
||||
});
|
||||
}
|
||||
|
||||
private void OnLateUpdate()
|
||||
{
|
||||
_updateDuration = _stopwatch.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
private void RenderPipelineOnBeginFrameRendering(ScriptableRenderContext context, Camera[] cameras)
|
||||
#else
|
||||
private void RenderPipelineOnBeginFrameRendering(Camera[] obj)
|
||||
#endif
|
||||
{
|
||||
_renderStartTime = _stopwatch.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
private void EndFrame()
|
||||
{
|
||||
if (_stopwatch.IsRunning)
|
||||
{
|
||||
PushFrame(_stopwatch.Elapsed.TotalSeconds, _updateDuration, _renderDuration);
|
||||
|
||||
_stopwatch.Reset();
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
_updateDuration = _renderDuration = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f6b60357b55b3a438c0f79ba2be864c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
59
JNFrame2/Assets/Plugins/SRDebugger/Scripts/SRDebug.cs
Normal file
59
JNFrame2/Assets/Plugins/SRDebugger/Scripts/SRDebug.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
#if UNITY_ANDROID || UNITY_IOS || UNITY_EDITOR || UNITY_STANDALONE
|
||||
#define COPY_TO_CLIPBOARD_SUPPORTED
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using SRDebugger.Services;
|
||||
using SRF.Service;
|
||||
using UnityEngine;
|
||||
|
||||
[assembly: InternalsVisibleTo("StompyRobot.SRDebugger.Editor")]
|
||||
|
||||
public static class SRDebug
|
||||
{
|
||||
public const string Version = SRDebugger.VersionInfo.Version;
|
||||
|
||||
public static bool IsInitialized { get; private set; }
|
||||
|
||||
public static IDebugService Instance
|
||||
{
|
||||
get { return SRServiceManager.GetService<IDebugService>(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action to be invoked whenever the user selects "copy" in the console window.
|
||||
/// If null, copy/paste will not be available.
|
||||
/// </summary>
|
||||
public static Action<ConsoleEntry> CopyConsoleItemCallback = GetDefaultCopyConsoleItemCallback();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
IsInitialized = true;
|
||||
|
||||
SRServiceManager.RegisterAssembly<IDebugService>();
|
||||
|
||||
// Initialize console if it hasn't already initialized.
|
||||
SRServiceManager.GetService<IConsoleService>();
|
||||
|
||||
// Load the debug service
|
||||
SRServiceManager.GetService<IDebugService>();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
SRDebugger.Scripts.Internal.SRScriptRecompileHelper.SetHasInitialized();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Action<ConsoleEntry> GetDefaultCopyConsoleItemCallback()
|
||||
{
|
||||
#if COPY_TO_CLIPBOARD_SUPPORTED
|
||||
return entry =>
|
||||
{
|
||||
GUIUtility.systemCopyBuffer =
|
||||
string.Format("{0}: {1}\n\r\n\r{2}", entry.LogType, entry.Message, entry.StackTrace);
|
||||
};
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 469b426fd7f6b90459d78fc3a5b1360b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
19
JNFrame2/Assets/Plugins/SRDebugger/Scripts/SRDebuggerInit.cs
Normal file
19
JNFrame2/Assets/Plugins/SRDebugger/Scripts/SRDebuggerInit.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
using SRF;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Add this component somewhere in your scene to automatically load SRDebugger when the scene is loaded.
|
||||
/// By default, SRDebugger will defer loading any UI except the corner-trigger until the user requests it.
|
||||
/// It is recommended to add this to the very first scene in your game. This will ensure the console log
|
||||
/// will hold useful information about your game initialization.
|
||||
/// </summary>
|
||||
[AddComponentMenu("")]
|
||||
[Obsolete("No longer required, use Automatic initialization mode or call SRDebug.Init() manually.")]
|
||||
public class SRDebuggerInit : SRMonoBehaviourEx
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66edd3610b01cce48aed05383fd196e5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -31999
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace SRDebugger
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class NumberRangeAttribute : Attribute
|
||||
{
|
||||
public readonly double Max;
|
||||
public readonly double Min;
|
||||
|
||||
public NumberRangeAttribute(double min, double max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class IncrementAttribute : Attribute
|
||||
{
|
||||
public readonly double Increment;
|
||||
|
||||
public IncrementAttribute(double increment)
|
||||
{
|
||||
Increment = increment;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
|
||||
public class SortAttribute : Attribute
|
||||
{
|
||||
public readonly int SortPriority;
|
||||
|
||||
public SortAttribute(int priority)
|
||||
{
|
||||
SortPriority = priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07d851b2833fe2d418d42519e51fac5f
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
* This file has been moved to StoryRobot/SROptions/SROptions.Test.cs
|
||||
* This empty file is left here to ensure it is properly overwritten when importing a new version of the package over an old version.
|
||||
*/
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f7d209d96c186e488b96fa4cd40c808
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
4
JNFrame2/Assets/Plugins/SRDebugger/Scripts/SROptions.cs
Normal file
4
JNFrame2/Assets/Plugins/SRDebugger/Scripts/SROptions.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
* This file has been moved to StoryRobot/SROptions/SROptions.cs
|
||||
* This empty file is left here to ensure it is properly overwritten when importing a new version of the package over an old version.
|
||||
*/
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93395ab8f46722d4eb96829e8d652a66
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Services.meta
Normal file
5
JNFrame2/Assets/Plugins/SRDebugger/Scripts/Services.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d056f36651c5f924abf693d27338ded5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Services
|
||||
{
|
||||
public sealed class ConsoleFilterStateService
|
||||
{
|
||||
public event ConsoleStateChangedEventHandler FilterStateChange;
|
||||
|
||||
private bool[] _states;
|
||||
|
||||
public ConsoleFilterStateService()
|
||||
{
|
||||
_states = new bool[Enum.GetValues(typeof(LogType)).Length];
|
||||
for (var i = 0; i < _states.Length; i++)
|
||||
{
|
||||
_states[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether log messages with <paramref name="logType"/> severity
|
||||
/// should be displayed in the SRDebugger console.
|
||||
/// </summary>
|
||||
/// <param name="logType">Type of message (only Error/Warning/Log are used. <see cref="LogType.Exception"/> and <see cref="LogType.Assert"/> will redirect to <see cref="LogType.Error"/></param>
|
||||
/// <param name="enabled">True to display the log type, false to hide.</param>
|
||||
public void SetState(LogType type, bool newState)
|
||||
{
|
||||
type = GetType(type);
|
||||
if (_states[(int)type] == newState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_states[(int)type] = newState;
|
||||
FilterStateChange?.Invoke(type, newState);
|
||||
}
|
||||
|
||||
public bool GetState(LogType type)
|
||||
{
|
||||
type = GetType(type);
|
||||
return _states[(int)type];
|
||||
}
|
||||
|
||||
private static LogType GetType(LogType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LogType.Error:
|
||||
case LogType.Assert:
|
||||
case LogType.Exception:
|
||||
return LogType.Error;
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec12e06d2d613ab49995ac63bec8fd01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace SRDebugger.Services
|
||||
{
|
||||
public delegate void BugReportCompleteCallback(bool didSucceed, string errorMessage);
|
||||
|
||||
public delegate void BugReportProgressCallback(float progress);
|
||||
|
||||
public interface IBugReportService
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the bug reporter is available for use right now.
|
||||
/// </summary>
|
||||
bool IsUsable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Set the handler that will submit bug reports.
|
||||
/// </summary>
|
||||
void SetHandler(IBugReporterHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// Submit a bug report.
|
||||
/// completeHandler can be invoked any time after the method is called
|
||||
/// (even before the method has returned in case of no internet).
|
||||
/// </summary>
|
||||
/// <param name="report">Bug report to send</param>
|
||||
/// <param name="completeHandler">Delegate to call once bug report is submitted successfully</param>
|
||||
/// <param name="progressCallback">Optionally provide a callback for when progress % is known</param>
|
||||
void SendBugReport(BugReport report, BugReportCompleteCallback completeHandler,
|
||||
IProgress<float> progressCallback = null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fea92fa06a1807f40a783c5e315e79cf
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SRDebugger.Services
|
||||
{
|
||||
public delegate void ConsoleStateChangedEventHandler(LogType logType, bool newState);
|
||||
|
||||
public interface IConsoleFilterState
|
||||
{
|
||||
event ConsoleStateChangedEventHandler FilterStateChange;
|
||||
|
||||
/// <summary>
|
||||
/// Set whether log messages with <paramref name="logType"/> severity
|
||||
/// should be displayed in the SRDebugger console.
|
||||
/// </summary>
|
||||
/// <param name="logType">Type of message (only Error/Warning/Log are used. <see cref="LogType.Exception"/> and <see cref="LogType.Assert"/> will redirect to <see cref="LogType.Error"/></param>
|
||||
/// <param name="enabled">True to display the log type, false to hide.</param>
|
||||
void SetConsoleFilterState(LogType logType, bool enabled);
|
||||
|
||||
/// <summary>
|
||||
/// Get whether log messages with <paramref name="logType"/> severity are
|
||||
/// being displayed in the SRDebugger console.
|
||||
/// </summary>
|
||||
/// <param name="logType">Type of message (only Error/Warning/Log are used. <see cref="LogType.Exception"/> and <see cref="LogType.Assert"/> will redirect to <see cref="LogType.Error"/></param>
|
||||
/// <returns>True if the log type is displayed.</returns>
|
||||
bool GetConsoleFilterState(LogType logType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24e4816cd1ac23a4a9e6cc452eab0494
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SRDebugger.Services
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
public delegate void ConsoleUpdatedEventHandler(IConsoleService console);
|
||||
|
||||
public interface IConsoleService
|
||||
{
|
||||
int ErrorCount { get; }
|
||||
int WarningCount { get; }
|
||||
int InfoCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of ConsoleEntry objects since the last clear.
|
||||
/// </summary>
|
||||
IReadOnlyList<ConsoleEntry> Entries { get; }
|
||||
|
||||
/// <summary>
|
||||
/// List of all ConsoleEntry objects, regardless of clear.
|
||||
/// </summary>
|
||||
IReadOnlyList<ConsoleEntry> AllEntries { get; }
|
||||
|
||||
event ConsoleUpdatedEventHandler Updated;
|
||||
|
||||
event ConsoleUpdatedEventHandler Error;
|
||||
|
||||
bool LoggingEnabled { get; set; }
|
||||
|
||||
bool LogHandlerIsOverriden { get; }
|
||||
|
||||
void Clear();
|
||||
}
|
||||
|
||||
public class ConsoleEntry
|
||||
{
|
||||
private const int MessagePreviewLength = 180;
|
||||
private const int StackTracePreviewLength = 120;
|
||||
private string _messagePreview;
|
||||
private string _stackTracePreview;
|
||||
|
||||
/// <summary>
|
||||
/// Number of times this log entry has occured (if collapsing is enabled)
|
||||
/// </summary>
|
||||
public int Count = 1;
|
||||
|
||||
public LogType LogType;
|
||||
public string Message;
|
||||
public string StackTrace;
|
||||
public ConsoleEntry() {}
|
||||
|
||||
public ConsoleEntry(ConsoleEntry other)
|
||||
{
|
||||
Message = other.Message;
|
||||
StackTrace = other.StackTrace;
|
||||
LogType = other.LogType;
|
||||
Count = other.Count;
|
||||
}
|
||||
|
||||
public string MessagePreview
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_messagePreview != null)
|
||||
{
|
||||
return _messagePreview;
|
||||
}
|
||||
if (string.IsNullOrEmpty(Message))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
_messagePreview = Message.Split('\n')[0];
|
||||
_messagePreview = _messagePreview.Substring(0, Mathf.Min(_messagePreview.Length, MessagePreviewLength));
|
||||
|
||||
return _messagePreview;
|
||||
}
|
||||
}
|
||||
|
||||
public string StackTracePreview
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stackTracePreview != null)
|
||||
{
|
||||
return _stackTracePreview;
|
||||
}
|
||||
if (string.IsNullOrEmpty(StackTrace))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
_stackTracePreview = StackTrace.Split('\n')[0];
|
||||
_stackTracePreview = _stackTracePreview.Substring(0,
|
||||
Mathf.Min(_stackTracePreview.Length, StackTracePreviewLength));
|
||||
|
||||
return _stackTracePreview;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Matches(ConsoleEntry other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return string.Equals(Message, other.Message) && string.Equals(StackTrace, other.StackTrace) &&
|
||||
LogType == other.LogType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60ae196448d0a9549859c96c7ed8b974
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user