/// <summary> /// Investigate a specific subscription. /// </summary> /// /// <param name="subscription">The <see cref="Subscription"/> descriptor to inspect.</param> /// /// <param name="log">The log file where results are sent.</param> private static void Investigate(Subscription subscription, ref StringBuilder log) { Review review = subscription.Review; Version gameVersion = GameVersion.Active; LogHeader(subscription, ref log); if (!subscription.IsEnabled) { log.Append("\n - It is disabled; if not using it, it should be unsubscribed.\n"); } if (!subscription.IsReviewed) { log.Append("\n - This mod has not been reviewed yet.\n"); if (Options.Instance.LogWorkshopURLs) { log.AppendFormat("\n - Workshop page: {0}\n", subscription.WorkshopURL); } return; } if (Options.Instance.LogDescriptorHeaders) { log.AppendFormat( "\n - [AutoRepair Descriptor] Catalog: '{0}'. Vectors: {1}. Author(s): {2}\n ", review.Catalog, review.Compatibility.Count, review.Authors); if (review.Published != null) { log.AppendFormat("Published: {0:d MMM yyyy}. ", review.Published); } if (review.Updated != null) { log.AppendFormat("Updated: {0:d MMM yyyy}. ", review.Updated); } if (review.LastSeen != null) { log.AppendFormat("Checked: {0:d MMM yyyy}. ", review.LastSeen); } if (review.Removed != null) { log.AppendFormat("Removed: {0:d MMM yyyy}. ", review.Removed); } log.AppendFormat("Downloaded: {0:d MMM yyyy}.\n", subscription.Downloaded); } if (review.BrokenBy != null && gameVersion >= review.BrokenBy) { log.AppendFormat( "\n - Broken by the Cities: Skylines {0} update.\n", GameVersion.GetVersionString(review.BrokenBy)); } else if (review.HasFlag(ItemFlags.GameBreaking)) { log.Append("\n - Broken. Unsubscribe it.\n"); } else if (review.CompatibleWith != null && GameVersion.LatestMilestone <= review.CompatibleWith) { log.AppendFormat( "\n - Compatible with Cities: Skylines {0} :)\n", GameVersion.GetVersionString(gameVersion)); } else { log.AppendFormat( "\n - Probably compatible with Cities: Skylines {0} ?\n", GameVersion.GetVersionString(gameVersion)); } if (Options.Instance.LogWorkshopURLs) { if (!string.IsNullOrEmpty(review.ArchiveURL)) { log.AppendFormat("\n - Archive of removed workshop page: {0}\n", review.ArchiveURL); } else if (review.HasFlag(ItemFlags.NoWorkshop)) { log.Append("\n - Removed from Steam Workshop; it is probably obsolete or game breaking.\n"); } else { log.AppendFormat("\n - Workshop page: {0}\n", subscription.WorkshopURL); } } if (review.HasFlag(ItemFlags.EditorBreaking)) { log.Append("\n - Breaks content editors; before using editors, disable it and exit to desktop to flush it from RAM.\n"); } if (review.HasFlag(ItemFlags.Abandonware)) { log.Append("\n - Mod seems (or is) abandonned; future updates are unlikely.\n"); } if (review.HasFlag(ItemFlags.Streamable)) { log.Append("\n - Safe for streaming (according to author / music source).\n"); } else if (review.Compatibility.TryGetValue(422934383u, out var status)) { if (status == Status.Required) { log.Append("\n - Not safe for streaming (copyrighted music).\n"); } } if (review.HasFlag(ItemFlags.Laggy)) { log.Append("\n - Can cause performance issues (lag or framerate drop in-game).\n"); } if (review.HasFlag(ItemFlags.SlowLoad)) { log.Append("\n - Can increase time taken to load save games.\n"); } if (review.HasFlag(ItemFlags.LargeFileWarning)) { log.Append("\n - Large file size compared to other items of same type.\n"); } if (review.HasFlag(ItemFlags.MinorIssues)) { log.Append("\n - Minor issues - check workshop page/comments for details.\n"); } if (review.HasFlag(ItemFlags.SaveAltering)) { log.Append("\n - Alters the save game; without it, the savegame might break.\n"); } if (review.HasFlag(ItemFlags.Unreliable)) { log.Append("\n - Some users experienced problems; check workshop page/comments for details.\n"); } if (Options.Instance.LogLanguages) { if (review.Languages != null) { log.AppendFormat( "\n - Locales: {0}\n", string.Join(", ", Locale.FromStringArray(review.Languages).ToArray())); } log.AppendFormat("\n - Primary locale: {0}\n", Locale.ToString(review.Locale)); } if (Options.Instance.LogSourceURLs) { if (review.HasFlag(ItemFlags.SourceAvailable)) { if (!string.IsNullOrEmpty(review.SourceURL)) { log.AppendFormat("\n - Source available: {0}\n", review.SourceURL); } if (review.HasFlag(ItemFlags.SourceOudated)) { log.Append("\n - The available source code hasn't been kept up-to-date with recent mod updates.\n"); } } else if (review.HasFlag(ItemFlags.SourceBundled)) { log.Append("\n - Source is bundled in its 'Source' folder.\n"); if (Application.platform == RuntimePlatform.OSXPlayer) { log.Append("\n - Mac users: If this item doesn't contain pre-compiled files, it might not work on OS/X.\n"); } } else if (review.HasFlag(ItemFlags.SourceUnavailable)) { // todo: check for `Source` folder in mod folder log.Append("\n - No source code/files found (yet); future updates will be difficult.\n"); } } if (review.HasFlag(ItemFlags.SourceObfuscated)) { log.Append("\n - WARNING: Source code is obfuscated, preventing inspection!\n"); } if (review.Compatibility != null && review.Compatibility.Count > 0) { ScanCompatibility(review, ref log); } if (review.Notes != null) { foreach (var note in review.Notes) { if (IsAlwaysNote(note.Key) || IsSubscribed(note.Key)) { log.AppendFormat("\n - {0}\n", note.Value); } } } if (review.ReplaceWith != 0u) { SuggestReplacement(review, ref log); } }