607 lines
32 KiB
C#
607 lines
32 KiB
C#
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<AlertEntry> eventsTimeline = new List<AlertEntry>();
|
|
internal static List<AlertEntry> 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<PersistedAlertData>(File.ReadAllText(filePath));
|
|
eventsTimeline = new List<AlertEntry>(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<AlertEntry>();
|
|
}
|
|
|
|
internal static readonly Dictionary<AlertType, string> alertIconString = new Dictionary<AlertType, string> {
|
|
{ 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<PartiallySupportedChange, string> partiallySupportedChangeDescriptions => new Dictionary<PartiallySupportedChange, string> {
|
|
{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<AlertEntry> Suggestions = new List<AlertEntry>();
|
|
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<AlertEntry> expandedEntries = new List<AlertEntry>();
|
|
|
|
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>(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);
|
|
}
|
|
}
|
|
}
|
|
}
|