提交Unity 联机Pro

This commit is contained in:
PC-20230316NUNE\Administrator
2024-08-17 14:27:18 +08:00
parent f00193b000
commit 894100ae37
7448 changed files with 854473 additions and 0 deletions

View 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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c678ba20e05678942905f13f1f42c8e1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -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();
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 58b4c2d8acab3b747a2a90abd77b1132
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fab9c606533743f6bfcb59f8392b1a0c
timeCreated: 1611921984

View 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;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4b80f539792faff4187cbd7fb1113d67
timeCreated: 1451840376
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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.
*/

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c38092124e5b1114d9f037f64769dc5f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -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;
}
}
}
}

View File

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

View File

@@ -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");
}
}
}
}

View File

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

View File

@@ -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);
});
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ca60d3f1302b47e1a3c6f43ed06dedcf
timeCreated: 1611413144

View File

@@ -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";
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6eeabd6854ed440ab38998300a297c0b
timeCreated: 1611414784

View File

@@ -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.";
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cd05741ba3454346864f3c28fcdce56f
timeCreated: 1611414505

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8d3667acfb91436880aa7f35bcc5fe43
timeCreated: 1611919957

View File

@@ -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;
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f05cd73b58c9481593f90b04c3084b15
timeCreated: 1611414371

View File

@@ -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
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c10ec5c3e9f1e404ba655cbc07340b94
timeCreated: 1465649914
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6304f38f53dfcc44f9265410f0f14050
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3a6cf957f3eda7b429dd0eae2cfbb40c
timeCreated: 1441902550
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
{
"name": "StompyRobot.SRDebugger.Editor",
"references": [
"StompyRobot.SRDebugger",
"StompyRobot.SRF"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": []
}

View File

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

View File

@@ -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

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1e35f7047e81c2247ae9a5bfd682e156
timeCreated: 1442417928
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: