using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using JetBrains.Annotations; using SingularityGroup.HotReload.DTO; using SingularityGroup.HotReload.Localization; using SingularityGroup.HotReload.Newtonsoft.Json; using UnityEditor; using UnityEngine; using Translations = SingularityGroup.HotReload.Editor.Localization.Translations; namespace SingularityGroup.HotReload.Editor { internal enum TimelineType { Suggestions, Timeline, } internal enum AlertType { Suggestion, UnsupportedChange, CompileError, PartiallySupportedChange, AppliedChange, UndetectedChange, } internal enum AlertEntryType { Error, Failure, InlinedMethod, PatchApplied, PartiallySupportedChange, UndetectedChange, } internal enum EntryType { Parent, Child, Standalone, Foldout, } internal class PersistedAlertData { public readonly AlertData[] alertDatas; public PersistedAlertData(AlertData[] alertDatas) { this.alertDatas = alertDatas; } } internal class AlertData { public readonly AlertEntryType alertEntryType; public readonly string errorString; public readonly string methodName; public readonly string methodSimpleName; public readonly PartiallySupportedChange partiallySupportedChange; public readonly EntryType entryType; public readonly bool detiled; public readonly DateTime createdAt; public readonly string[] patchedMembersDisplayNames; public AlertData(AlertEntryType alertEntryType, DateTime createdAt, bool detiled = false, EntryType entryType = EntryType.Standalone, string errorString = null, string methodName = null, string methodSimpleName = null, PartiallySupportedChange partiallySupportedChange = default(PartiallySupportedChange), string[] patchedMembersDisplayNames = null) { this.alertEntryType = alertEntryType; this.createdAt = createdAt; this.detiled = detiled; this.entryType = entryType; this.errorString = errorString; this.methodName = methodName; this.methodSimpleName = methodSimpleName; this.partiallySupportedChange = partiallySupportedChange; this.patchedMembersDisplayNames = patchedMembersDisplayNames; } } internal class AlertEntry { internal readonly AlertType alertType; internal readonly string title; internal readonly DateTime timestamp; internal readonly string description; [CanBeNull] internal readonly Action actionData; internal readonly AlertType iconType; internal readonly string shortDescription; internal readonly EntryType entryType; internal readonly AlertData alertData; internal readonly bool hasExitButton; internal AlertEntry(AlertType alertType, string title, string description, DateTime timestamp, string shortDescription = null, Action actionData = null, AlertType? iconType = null, EntryType entryType = EntryType.Standalone, AlertData alertData = default(AlertData), bool hasExitButton = true) { this.alertType = alertType; this.title = title; this.description = description; this.shortDescription = shortDescription; this.actionData = actionData; this.iconType = iconType ?? alertType; this.timestamp = timestamp; this.entryType = entryType; this.alertData = alertData; this.hasExitButton = hasExitButton; } } internal static class HotReloadTimelineHelper { internal const int maxVisibleEntries = 40; private static List eventsTimeline = new List(); internal static List EventsTimeline => eventsTimeline; static readonly string filePath = Path.Combine(PackageConst.LibraryCachePath, "eventEntries.json"); public static void InitPersistedEvents() { if (!File.Exists(filePath)) { return; } var redDotShown = HotReloadState.ShowingRedDot; try { var persistedAlertData = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); eventsTimeline = new List(persistedAlertData.alertDatas.Length); for (int i = persistedAlertData.alertDatas.Length - 1; i >= 0; i--) { AlertData alertData = persistedAlertData.alertDatas[i]; switch (alertData.alertEntryType) { case AlertEntryType.Error: CreateErrorEventEntry(errorString: alertData.errorString, entryType: alertData.entryType, createdAt: alertData.createdAt); break; #if UNITY_2020_1_OR_NEWER case AlertEntryType.InlinedMethod: CreateInlinedMethodsEntry(alertData.patchedMembersDisplayNames, alertData.entryType, alertData.createdAt); break; #endif case AlertEntryType.Failure: if (alertData.entryType == EntryType.Parent) { CreateReloadFinishedWithWarningsEventEntry(createdAt: alertData.createdAt, patchedMembersDisplayNames: alertData.patchedMembersDisplayNames); } else { CreatePatchFailureEventEntry(errorString: alertData.errorString, methodName: alertData.methodName, methodSimpleName: alertData.methodSimpleName, entryType: alertData.entryType, createdAt: alertData.createdAt); } break; case AlertEntryType.PatchApplied: CreateReloadFinishedEventEntry( createdAt: alertData.createdAt, patchedMethodsDisplayNames: alertData.patchedMembersDisplayNames ); break; case AlertEntryType.PartiallySupportedChange: if (alertData.entryType == EntryType.Parent) { CreateReloadPartiallyAppliedEventEntry(createdAt: alertData.createdAt, patchedMethodsDisplayNames: alertData.patchedMembersDisplayNames); } else { CreatePartiallyAppliedEventEntry(alertData.partiallySupportedChange, entryType: alertData.entryType, detailed: alertData.detiled, createdAt: alertData.createdAt); } break; case AlertEntryType.UndetectedChange: CreateReloadUndetectedChangeEventEntry(createdAt: alertData.createdAt); break; } } } catch (Exception e) { Log.Warning(Translations.Errors.WarningInitializingEventEntries, e); } finally { // Ensure red dot is not triggered for existing entries HotReloadState.ShowingRedDot = redDotShown; } } internal static void PersistTimeline() { var alertDatas = new AlertData[eventsTimeline.Count]; for (var i = 0; i < eventsTimeline.Count; i++) { alertDatas[i] = eventsTimeline[i].alertData; } var persistedData = new PersistedAlertData(alertDatas); try { File.WriteAllText(path: filePath, contents: JsonConvert.SerializeObject(persistedData)); } catch (Exception e) { Log.Warning(Translations.Errors.WarningPersistingEventEntries, e); } } internal static void ClearPersistance() { try { File.Delete(filePath); } catch { // ignore } eventsTimeline = new List(); } internal static readonly Dictionary alertIconString = new Dictionary { { AlertType.Suggestion, "alert_info" }, { AlertType.UnsupportedChange, "warning" }, { AlertType.CompileError, "error" }, { AlertType.PartiallySupportedChange, "infos" }, { AlertType.AppliedChange, "applied_patch" }, { AlertType.UndetectedChange, "undetected" }, }; #pragma warning disable CS0612 // obsolete public static Dictionary partiallySupportedChangeDescriptions => new Dictionary { {PartiallySupportedChange.LambdaClosure, Translations.Timeline.PartiallySupportedLambdaClosure}, {PartiallySupportedChange.EditAsyncMethod, Translations.Timeline.PartiallySupportedEditAsyncMethod}, {PartiallySupportedChange.AddMonobehaviourMethod, Translations.Timeline.PartiallySupportedAddMonobehaviourMethod}, {PartiallySupportedChange.EditMonobehaviourField, Translations.Timeline.PartiallySupportedEditMonobehaviourField}, {PartiallySupportedChange.EditCoroutine, Translations.Timeline.PartiallySupportedEditCoroutine}, {PartiallySupportedChange.EditGenericFieldInitializer, Translations.Timeline.PartiallySupportedEditGenericFieldInitializer}, {PartiallySupportedChange.AddEnumMember, Translations.Timeline.PartiallySupportedAddEnumMember}, {PartiallySupportedChange.EditFieldInitializer, Translations.Timeline.PartiallySupportedEditFieldInitializer}, {PartiallySupportedChange.AddMethodWithAttributes, Translations.Timeline.PartiallySupportedAddMethodWithAttributes}, {PartiallySupportedChange.AddFieldWithAttributes, Translations.Timeline.PartiallySupportedAddFieldWithAttributes}, {PartiallySupportedChange.GenericMethodInGenericClass, Translations.Timeline.PartiallySupportedGenericMethodInGenericClass}, {PartiallySupportedChange.NewCustomSerializableField, Translations.Timeline.PartiallySupportedNewCustomSerializableField}, {PartiallySupportedChange.MultipleFieldsEditedInTheSameType, Translations.Timeline.PartiallySupportedMultipleFieldsEditedInTheSameType}, }; #pragma warning restore CS0612 internal static List Suggestions = new List(); internal static int UnsupportedChangesCount => EventsTimeline.Count(alert => alert.alertType == AlertType.UnsupportedChange && alert.entryType != EntryType.Child); internal static int PartiallySupportedChangesCount => EventsTimeline.Count(alert => alert.alertType == AlertType.PartiallySupportedChange && alert.entryType != EntryType.Child); internal static int UndetectedChangesCount => EventsTimeline.Count(alert => alert.alertType == AlertType.UndetectedChange && alert.entryType != EntryType.Child); internal static int CompileErrorsCount => EventsTimeline.Count(alert => alert.alertType == AlertType.CompileError); internal static int AppliedChangesCount => EventsTimeline.Count(alert => alert.alertType == AlertType.AppliedChange); static Regex shortDescriptionRegex = new Regex(PackageConst.DefaultLocale == Locale.SimplifiedChinese ? @"^([\p{L}\p{N}_]+)\s([\p{L}\p{N}_]+)(?=:)" : @"^(\w+)\s(\w+)(?=:)", RegexOptions.Compiled); internal static int GetRunTabTimelineEventCount() { int total = 0; if (HotReloadPrefs.RunTabUnsupportedChangesFilter) { total += UnsupportedChangesCount; } if (HotReloadPrefs.RunTabPartiallyAppliedPatchesFilter) { total += PartiallySupportedChangesCount; } if (HotReloadPrefs.RunTabUndetectedPatchesFilter) { total += UndetectedChangesCount; } if (HotReloadPrefs.RunTabCompileErrorFilter) { total += CompileErrorsCount; } if (HotReloadPrefs.RunTabAppliedPatchesFilter) { total += AppliedChangesCount; } return total; } internal static List expandedEntries = new List(); internal static void RenderCompileButton() { if (GUILayout.Button(Translations.Common.ButtonRecompile.Trim(), GUILayout.Width(80))) { HotReloadRunTab.RecompileWithChecks(); } } private static float maxScrollPos; internal static void RenderErrorEventActions(string description, ErrorData errorData) { int maxLen = 2400; string text = errorData.stacktrace; if (text.Length > maxLen) { text = text.Substring(0, maxLen) + "..."; } GUILayout.TextArea(text, HotReloadWindowStyles.StacktraceTextAreaStyle); if (errorData.file || !errorData.stacktrace.Contains("error CS")) { GUILayout.Space(10f); } using (new EditorGUILayout.HorizontalScope()) { if (!errorData.stacktrace.Contains("error CS")) { RenderCompileButton(); } // Link if (errorData.file) { GUILayout.FlexibleSpace(); if (GUILayout.Button(errorData.linkString, HotReloadWindowStyles.LinkStyle)) { AssetDatabase.OpenAsset(errorData.file, Math.Max(errorData.lineNumber, 1)); } } } } private static Texture2D GetFilterIcon(int count, AlertType alertType) { if (count == 0) { return GUIHelper.ConvertToGrayscale(alertIconString[alertType]); } return GUIHelper.GetLocalIcon(alertIconString[alertType]); } internal static void RenderAlertFilters() { using (new EditorGUILayout.HorizontalScope()) { var text = AppliedChangesCount > 999 ? "999+" : " " + AppliedChangesCount; HotReloadPrefs.RunTabAppliedPatchesFilter = GUILayout.Toggle( HotReloadPrefs.RunTabAppliedPatchesFilter, new GUIContent(text, GetFilterIcon(AppliedChangesCount, AlertType.AppliedChange)), HotReloadWindowStyles.EventFiltersStyle); GUILayout.Space(-1f); text = UndetectedChangesCount > 999 ? "999+" : " " + UndetectedChangesCount; HotReloadPrefs.RunTabUndetectedPatchesFilter = GUILayout.Toggle( HotReloadPrefs.RunTabUndetectedPatchesFilter, new GUIContent(text, GetFilterIcon(UnsupportedChangesCount, AlertType.UndetectedChange)), HotReloadWindowStyles.EventFiltersStyle); GUILayout.Space(-1f); text = PartiallySupportedChangesCount > 999 ? "999+" : " " + PartiallySupportedChangesCount; HotReloadPrefs.RunTabPartiallyAppliedPatchesFilter = GUILayout.Toggle( HotReloadPrefs.RunTabPartiallyAppliedPatchesFilter, new GUIContent(text, GetFilterIcon(PartiallySupportedChangesCount, AlertType.PartiallySupportedChange)), HotReloadWindowStyles.EventFiltersStyle); GUILayout.Space(-1f); text = UnsupportedChangesCount > 999 ? "999+" : " " + UnsupportedChangesCount; HotReloadPrefs.RunTabUnsupportedChangesFilter = GUILayout.Toggle( HotReloadPrefs.RunTabUnsupportedChangesFilter, new GUIContent(text, GetFilterIcon(UnsupportedChangesCount, AlertType.UnsupportedChange)), HotReloadWindowStyles.EventFiltersStyle); GUILayout.Space(-1f); text = CompileErrorsCount > 999 ? "999+" : " " + CompileErrorsCount; HotReloadPrefs.RunTabCompileErrorFilter = GUILayout.Toggle( HotReloadPrefs.RunTabCompileErrorFilter, new GUIContent(text, GetFilterIcon(CompileErrorsCount, AlertType.CompileError)), HotReloadWindowStyles.EventFiltersStyle); } } internal static void CreateErrorEventEntry(string errorString, EntryType entryType = EntryType.Standalone, DateTime? createdAt = null) { var timestamp = createdAt ?? DateTime.Now; var alertType = errorString.Contains("error CS") ? AlertType.CompileError : AlertType.UnsupportedChange; var title = errorString.Contains("error CS") ? Translations.Utility.CompileError : Translations.Utility.UnsupportedChange; ErrorData errorData = ErrorData.GetErrorData(errorString); var description = errorData.error; string shortDescription = null; if (alertType != AlertType.CompileError) { shortDescription = shortDescriptionRegex.Match(description).Value; } Action actionData = () => RenderErrorEventActions(description, errorData); InsertEntry(new AlertEntry( timestamp: timestamp, alertType: alertType, title: title, description: description, shortDescription: shortDescription, actionData: actionData, entryType: entryType, alertData: new AlertData(AlertEntryType.Error, createdAt: timestamp, errorString: errorString, entryType: entryType) )); } #if UNITY_2020_1_OR_NEWER internal static void CreateInlinedMethodsEntry(string[] patchedMethodsDisplayNames, EntryType entryType = EntryType.Standalone, DateTime? createdAt = null) { var truncated = false; if (patchedMethodsDisplayNames?.Length > 25) { patchedMethodsDisplayNames = TruncateList(patchedMethodsDisplayNames, 25); truncated = true; } var patchesList = patchedMethodsDisplayNames?.Length > 0 ? string.Join("\n• ", patchedMethodsDisplayNames) : ""; var timestamp = createdAt ?? DateTime.Now; var entry = new AlertEntry( timestamp: timestamp, alertType : AlertType.UnsupportedChange, title: Translations.Timeline.EventTitleFailedApplyingPatch, description: $"{Translations.Timeline.EventDescriptionInlinedMethods}\n\n• {(truncated ? patchesList + "\n..." : patchesList)}", entryType: EntryType.Parent, actionData: () => { GUILayout.Space(10f); using (new EditorGUILayout.HorizontalScope()) { RenderCompileButton(); var suggestion = HotReloadSuggestionsHelper.suggestionMap[HotReloadSuggestionKind.SwitchToDebugModeForInlinedMethods]; if (suggestion?.actionData != null) { suggestion.actionData(); } } }, alertData: new AlertData(AlertEntryType.InlinedMethod, createdAt: timestamp, patchedMembersDisplayNames: patchedMethodsDisplayNames, entryType: EntryType.Parent) ); InsertEntry(entry); if (patchedMethodsDisplayNames?.Length > 0) { expandedEntries.Add(entry); } } #endif internal static void CreatePatchFailureEventEntry(string errorString, string methodName, string methodSimpleName = null, EntryType entryType = EntryType.Standalone, DateTime? createdAt = null) { var timestamp = createdAt ?? DateTime.Now; ErrorData errorData = ErrorData.GetErrorData(errorString); var title = Translations.Timeline.EventTitleFailedApplyingPatch; Action actionData = () => RenderErrorEventActions(errorData.error, errorData); InsertEntry(new AlertEntry( timestamp: timestamp, alertType : AlertType.UnsupportedChange, title: title, description: string.Format(Translations.Timeline.EventDescriptionFailedApplyingPatchTapForMore, title, methodName), shortDescription: methodSimpleName, actionData: actionData, entryType: entryType, alertData: new AlertData(AlertEntryType.Failure, createdAt: timestamp, errorString: errorString, methodName: methodName, methodSimpleName: methodSimpleName, entryType: entryType) )); } public static T[] TruncateList(T[] originalList, int len) { if (originalList.Length <= len) { return originalList; } // Create a new list with a maximum of 25 items T[] truncatedList = new T[len]; for (int i = 0; i < originalList.Length && i < len; i++) { truncatedList[i] = originalList[i]; } return truncatedList; } internal static void CreateReloadFinishedEventEntry(DateTime? createdAt = null, string[] patchedMethodsDisplayNames = null) { var truncated = false; if (patchedMethodsDisplayNames?.Length > 25) { patchedMethodsDisplayNames = TruncateList(patchedMethodsDisplayNames, 25); truncated = true; } var patchesList = patchedMethodsDisplayNames?.Length > 0 ? string.Join("\n• ", patchedMethodsDisplayNames) : ""; var timestamp = createdAt ?? DateTime.Now; var entry = new AlertEntry( timestamp: timestamp, alertType: AlertType.AppliedChange, title: EditorIndicationState.IndicationText[EditorIndicationState.IndicationStatus.Reloaded], description: patchedMethodsDisplayNames?.Length > 0 ? $"• {(truncated ? patchesList + "\n..." : patchesList)}" : Translations.Timeline.EventDescriptionNoIssuesFound, entryType: patchedMethodsDisplayNames?.Length > 0 ? EntryType.Parent : EntryType.Standalone, alertData: new AlertData( AlertEntryType.PatchApplied, createdAt: timestamp, entryType: EntryType.Standalone, patchedMembersDisplayNames: patchedMethodsDisplayNames) ); InsertEntry(entry); if (patchedMethodsDisplayNames?.Length > 0) { expandedEntries.Add(entry); } } internal static void CreateReloadFinishedWithWarningsEventEntry(DateTime? createdAt = null, string[] patchedMembersDisplayNames = null) { var truncated = false; if (patchedMembersDisplayNames?.Length > 25) { patchedMembersDisplayNames = TruncateList(patchedMembersDisplayNames, 25); truncated = true; } var patchesList = patchedMembersDisplayNames?.Length > 0 ? string.Join("\n• ", patchedMembersDisplayNames) : ""; var timestamp = createdAt ?? DateTime.Now; var entry = new AlertEntry( timestamp: timestamp, alertType: AlertType.UnsupportedChange, title: EditorIndicationState.IndicationText[EditorIndicationState.IndicationStatus.Unsupported], description: patchedMembersDisplayNames?.Length > 0 ? $"• {(truncated ? patchesList + "\n...\n\n" + Translations.Timeline.EventDescriptionSeeUnsupportedChangesBelow : patchesList + "\n\n" + Translations.Timeline.EventDescriptionSeeUnsupportedChangesBelow)}" : Translations.Timeline.EventDescriptionSeeDetailedEntriesBelow, entryType: EntryType.Parent, alertData: new AlertData(AlertEntryType.Failure, createdAt: timestamp, entryType: EntryType.Parent, patchedMembersDisplayNames: patchedMembersDisplayNames) ); InsertEntry(entry); if (patchedMembersDisplayNames?.Length > 0) { expandedEntries.Add(entry); } } internal static void CreateReloadPartiallyAppliedEventEntry(DateTime? createdAt = null, string[] patchedMethodsDisplayNames = null) { var truncated = false; if (patchedMethodsDisplayNames?.Length > 25) { patchedMethodsDisplayNames = TruncateList(patchedMethodsDisplayNames, 25); truncated = true; } var patchesList = patchedMethodsDisplayNames?.Length > 0 ? string.Join("\n• ", patchedMethodsDisplayNames) : ""; var timestamp = createdAt ?? DateTime.Now; var entry = new AlertEntry( timestamp: timestamp, alertType: AlertType.PartiallySupportedChange, title: EditorIndicationState.IndicationText[EditorIndicationState.IndicationStatus.PartiallySupported], description: patchedMethodsDisplayNames?.Length > 0 ? $"• {(truncated ? patchesList + "\n...\n\n" + Translations.Timeline.EventDescriptionSeePartiallyAppliedChangesBelow : patchesList + "\n\n" + Translations.Timeline.EventDescriptionSeePartiallyAppliedChangesBelow)}" : Translations.Timeline.EventDescriptionSeeDetailedEntriesBelow, entryType: EntryType.Parent, alertData: new AlertData(AlertEntryType.PartiallySupportedChange, createdAt: timestamp, entryType: EntryType.Parent, patchedMembersDisplayNames: patchedMethodsDisplayNames) ); InsertEntry(entry); if (patchedMethodsDisplayNames?.Length > 0) { expandedEntries.Add(entry); } } internal static void CreateReloadUndetectedChangeEventEntry(DateTime? createdAt = null) { var timestamp = createdAt ?? DateTime.Now; InsertEntry(new AlertEntry( timestamp: timestamp, alertType : AlertType.UndetectedChange, title: EditorIndicationState.IndicationText[EditorIndicationState.IndicationStatus.Undetected], description: Translations.Timeline.EventDescriptionUndetectedChange, actionData: () => { GUILayout.Space(10f); using (new EditorGUILayout.HorizontalScope()) { RenderCompileButton(); GUILayout.FlexibleSpace(); OpenURLButton.Render(Translations.Suggestions.ButtonDocs, Constants.UndetectedChangesURL); GUILayout.Space(10f); } }, entryType: EntryType.Foldout, alertData: new AlertData(AlertEntryType.UndetectedChange, createdAt: timestamp, entryType: EntryType.Parent) )); } internal static void CreatePartiallyAppliedEventEntry(PartiallySupportedChange partiallySupportedChange, EntryType entryType = EntryType.Standalone, bool detailed = true, DateTime? createdAt = null) { var timestamp = createdAt ?? DateTime.Now; string description; if (!partiallySupportedChangeDescriptions.TryGetValue(partiallySupportedChange, out description)) { return; } InsertEntry(new AlertEntry( timestamp: timestamp, alertType : AlertType.PartiallySupportedChange, title : detailed ? Translations.Timeline.EventTitleChangePartiallyApplied : ToString(partiallySupportedChange), description : description, shortDescription: detailed ? ToString(partiallySupportedChange) : null, actionData: () => { GUILayout.Space(10f); using (new EditorGUILayout.HorizontalScope()) { RenderCompileButton(); GUILayout.FlexibleSpace(); if (GetPartiallySupportedChangePref(partiallySupportedChange)) { if (GUILayout.Button(Translations.Timeline.ButtonIgnoreEventType, HotReloadWindowStyles.LinkStyle)) { HidePartiallySupportedChange(partiallySupportedChange); HotReloadRunTab.RepaintInstant(); } } } }, entryType: entryType, alertData: new AlertData(AlertEntryType.PartiallySupportedChange, createdAt: timestamp, partiallySupportedChange: partiallySupportedChange, entryType: entryType, detiled: detailed) )); } internal static void InsertEntry(AlertEntry entry) { eventsTimeline.Insert(0, entry); if (entry.alertType != AlertType.AppliedChange) { HotReloadState.ShowingRedDot = true; } } internal static void ClearEntries() { eventsTimeline.Clear(); } internal static bool GetPartiallySupportedChangePref(PartiallySupportedChange key) { return EditorPrefs.GetBool($"HotReloadWindow.ShowPartiallySupportedChangeType.{key}", true); } internal static void HidePartiallySupportedChange(PartiallySupportedChange key) { EditorPrefs.SetBool($"HotReloadWindow.ShowPartiallySupportedChangeType.{key}", false); // loop over scroll entries to remove hidden entries for (var i = EventsTimeline.Count - 1; i >= 0; i--) { var eventEntry = EventsTimeline[i]; if (eventEntry.alertData.partiallySupportedChange == key) { EventsTimeline.Remove(eventEntry); } } } // performance optimization (Enum.ToString uses reflection) internal static string ToString(this PartiallySupportedChange change) { #pragma warning disable CS0612 // obsolete switch (change) { case PartiallySupportedChange.LambdaClosure: return nameof(PartiallySupportedChange.LambdaClosure); case PartiallySupportedChange.EditAsyncMethod: return nameof(PartiallySupportedChange.EditAsyncMethod); case PartiallySupportedChange.AddMonobehaviourMethod: return nameof(PartiallySupportedChange.AddMonobehaviourMethod); case PartiallySupportedChange.EditMonobehaviourField: return nameof(PartiallySupportedChange.EditMonobehaviourField); case PartiallySupportedChange.EditCoroutine: return nameof(PartiallySupportedChange.EditCoroutine); case PartiallySupportedChange.EditGenericFieldInitializer: return nameof(PartiallySupportedChange.EditGenericFieldInitializer); case PartiallySupportedChange.AddEnumMember: return nameof(PartiallySupportedChange.AddEnumMember); case PartiallySupportedChange.EditFieldInitializer: return nameof(PartiallySupportedChange.EditFieldInitializer); case PartiallySupportedChange.AddMethodWithAttributes: return nameof(PartiallySupportedChange.AddMethodWithAttributes); case PartiallySupportedChange.GenericMethodInGenericClass: return nameof(PartiallySupportedChange.GenericMethodInGenericClass); case PartiallySupportedChange.AddFieldWithAttributes: return nameof(PartiallySupportedChange.AddFieldWithAttributes); case PartiallySupportedChange.NewCustomSerializableField: return nameof(PartiallySupportedChange.NewCustomSerializableField); case PartiallySupportedChange.MultipleFieldsEditedInTheSameType: return nameof(PartiallySupportedChange.MultipleFieldsEditedInTheSameType); #pragma warning restore CS0612 default: throw new ArgumentOutOfRangeException(nameof(change), change, null); } } } }