-
Notifications
You must be signed in to change notification settings - Fork 88
Updated compatibility checker #699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
originalfoo
wants to merge
24
commits into
master
Choose a base branch
from
697-608-439-compatibility-checker
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
57a03f3
wip - refactoring
originalfoo ca5b9af
use string builder for logging in loop
originalfoo d1fefff
Now compiles, showing signs of life
originalfoo e9a399d
cleaned some cruft
originalfoo 2c64dbb
tinkering with assembly scanner
originalfoo a757c28
DLC scanner added
originalfoo f472130
Tidy up, also added Match Day to DLC scanner
originalfoo 7d4ec20
Trying to extract version/branch info from assemblies
originalfoo 680ed97
Partially working reflection
originalfoo b679300
Almost completely working reflection!
originalfoo 70001e1
Retreiving version and branch, but very crufty code
originalfoo f1f8948
Version and branch inspection working nicely now
originalfoo a81d7e3
Missing variable declaration in example
originalfoo 385ddfd
mid-way through a refactor
originalfoo ea093f9
mid-refactor
originalfoo 2d2dfd8
Should be able to resume launcher auto-continue (not tested yet)
originalfoo 963c434
Merge branch 'master' into 697-608-439-compatibility-checker
originalfoo 8d6b87f
Tested the auto-continue feature - works great (thanks krzychu!)
originalfoo a287def
Refactor and cleanup
originalfoo 0e31dc8
mid-refactor of UI (still horrible broken mess)
originalfoo a488325
more refactoring
originalfoo 062c393
Tweaks to mod checker
originalfoo d31a3c1
Add error logging
originalfoo 5046b24
Minor tweaks
originalfoo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Submodule CSUtil.CameraControl
updated
from 420ec1 to a4b469
Submodule OptionsFramework
updated
from 802338 to 20d56e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| namespace TrafficManager.Compatibility.Check { | ||
| using ColossalFramework; | ||
| using ColossalFramework.Plugins; | ||
| using CSUtil.Commons; | ||
| using ICities; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Reflection; | ||
| using System.Text; | ||
| using System.Text.RegularExpressions; | ||
| using static ColossalFramework.Plugins.PluginManager; | ||
| using TrafficManager.Util; | ||
|
|
||
| public class Assemblies { | ||
|
|
||
| /// <summary> | ||
| /// Default build string if we can't determine LABS, STABLE, or DEBUG. | ||
| /// </summary> | ||
| internal const string OBSOLETE = "OBSOLETE"; | ||
|
|
||
| internal const string STABLE = "STABLE"; | ||
|
|
||
| internal const string BROKEN = "BROKEN"; | ||
|
|
||
| internal const string TMMOD = "TrafficManager.TrafficManagerMod"; | ||
|
|
||
| internal static readonly Version VersionedByAssembly; | ||
|
|
||
| internal static readonly Version LinuxFanVersion; | ||
|
|
||
| /// <summary> | ||
| /// Initializes static members of the <see cref="Assemblies"/> class. | ||
| /// </summary> | ||
| static Assemblies() { | ||
| VersionedByAssembly = new Version(11, 1, 0); | ||
| LinuxFanVersion = new Version(10, 20); | ||
| } | ||
|
|
||
| public static bool Verify(/*out Dictionary<Assembly,Guid> results*/) { | ||
|
|
||
| Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); | ||
| foreach (Assembly asm in assemblies) { | ||
| AssemblyName details = asm.GetName(); | ||
| if (details.Name.Contains("TrafficManager")) { | ||
|
|
||
| try { | ||
| //Log.Info("--------------------------- extracting ver info ---------------"); | ||
|
|
||
| if (ExtractVersionDetails(asm, out Version ver, out string build)) { | ||
| Log.InfoFormat( | ||
| "Assembly: {0} v{1} {2}", | ||
| details.Name, | ||
| ver.Build == -1 ? ver.ToString(2) : ver.ToString(3), | ||
| build); | ||
| } | ||
|
|
||
| } catch (Exception e) { | ||
| Log.Info("loop failed -----------"); | ||
| Log.Error(e.ToString()); | ||
| } | ||
| } | ||
| } | ||
| return true; // to do | ||
| } | ||
|
|
||
| internal static bool ExtractVersionDetails(Assembly asm, out Version ver, out string branch) { | ||
|
|
||
| ver = asm.GetName().Version; | ||
| branch = OBSOLETE; | ||
|
|
||
| Type type = asm.GetType(TMMOD); | ||
| object instance = Activator.CreateInstance(type); | ||
|
|
||
| if (ver < VersionedByAssembly) { | ||
| try { | ||
| if (MemberValue.TryGetMemberValue<string>(type, instance, "Version", out string dirty)) { | ||
| //Log.Info("Raw string: " + dirty); | ||
|
|
||
| // clean the raw string in to something that resembles a verison number | ||
| string clean = Regex.Match(dirty, @"[0-9]+(?:\.[0-9]+)+").Value; | ||
| //Log.Info("clean string: " + clean); | ||
|
|
||
| // parse in to Version instance | ||
| ver = new Version(clean); | ||
| } | ||
| } | ||
| catch { | ||
| Log.Warning("Unable to retrieve or parse 'Version' member"); | ||
| } | ||
| } | ||
|
|
||
| try { | ||
| if (MemberValue.TryGetMemberValue<string>(type, instance, "BRANCH", out string val)) { | ||
| branch = val; | ||
| } else if (ver == LinuxFanVersion) { // temporary | ||
| branch = STABLE; | ||
| } | ||
| } | ||
| catch { | ||
| Log.Warning("Unable to retrieve or parse 'BRANCH' member"); | ||
| } | ||
|
|
||
| (instance as IDisposable)?.Dispose(); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| namespace TrafficManager.Compatibility.Check { | ||
| using ColossalFramework.PlatformServices; | ||
| using CSUtil.Commons; | ||
| using System.Collections.Generic; | ||
| using System.Text; | ||
|
|
||
| /// <summary> | ||
| /// Scans for transit-affecting DLCs. | ||
| /// </summary> | ||
| public class DLCs { | ||
|
|
||
| /// <summary> | ||
| /// Scan for DLCs and log whether they are installed or not. | ||
| /// </summary> | ||
| public static void Verify() { | ||
|
|
||
| try { | ||
| Dictionary<uint, string> DLCs = new Dictionary<uint, string>() { | ||
| { (uint)SteamHelper.DLC.AfterDarkDLC, "After Dark" }, | ||
| { (uint)SteamHelper.DLC.InMotionDLC, "Mass Transit" }, | ||
| { (uint)SteamHelper.DLC.SnowFallDLC, "Snowfall" }, | ||
| { (uint)SteamHelper.DLC.NaturalDisastersDLC, "Natural Disasters" }, | ||
| { (uint)SteamHelper.DLC.ParksDLC, "Park Life" }, | ||
| { (uint)SteamHelper.DLC.IndustryDLC, "Industries" }, | ||
| { (uint)SteamHelper.DLC.GreenCitiesDLC, "Green Cities" }, | ||
| { (uint)SteamHelper.DLC.Football, "Match Day" }, | ||
| }; | ||
|
|
||
| StringBuilder sb = new StringBuilder(500); | ||
|
|
||
| sb.Append("Transit-affecting DLCs [*] = Installed:\n\n"); | ||
|
|
||
| string formatStr = " {0} {1}\n"; | ||
| string strAsterisk = "*"; | ||
| string strSpace = " "; | ||
|
|
||
| foreach (KeyValuePair<uint, string> dlc in DLCs) { | ||
| sb.AppendFormat( | ||
| formatStr, | ||
| PlatformService.IsDlcInstalled(dlc.Key) ? strAsterisk : strSpace, | ||
| dlc.Value); | ||
| } | ||
|
|
||
| Log.Info(sb.ToString()); | ||
| } | ||
| catch { | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| namespace TrafficManager.Compatibility.Check { | ||
| using ColossalFramework.Plugins; | ||
| using ColossalFramework; | ||
| using CSUtil.Commons; | ||
| using static ColossalFramework.Plugins.PluginManager; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Text; | ||
| using TrafficManager.Compatibility.Enum; | ||
| using TrafficManager.Compatibility.Struct; | ||
| using TrafficManager.State; | ||
|
|
||
| /// <summary> | ||
| /// Scans for known incompatible mods as defined by <see cref="IncompatibleMods.List"/>. | ||
| /// </summary> | ||
| public class Mods { | ||
|
|
||
| // Strings for log entries | ||
| internal const string LOG_ENTRY_FORMAT = "{0} {1} {2} {3}\n"; | ||
| internal const string MARKER_ENABLED = "*"; | ||
| internal const string MARKER_BLANK = " "; | ||
| internal const string MARKER_TMPE = ">"; | ||
| internal const string MARKER_CRITICAL = "C"; | ||
| internal const string MARKER_MAJOR = "M"; | ||
| internal const string MARKER_MINOR = "m"; | ||
|
|
||
| internal const string LOCAL_MOD_STR = "(local)"; | ||
| internal const string BUNDLED_MOD_STR = "(bundled)"; | ||
|
|
||
| /// <summary> | ||
| /// Scans installed mods (local and workshop) looking for known incompatibilities. | ||
| /// </summary> | ||
| /// | ||
| /// <param name="results">A dictionary issues found (will be empty if no issues).</param> | ||
| /// <param name="critical">Number of critical incompatibilities.</param> | ||
| /// <param name="major">Number of major incompatibilities.</param> | ||
| /// <param name="minor">Number of minor incompatibilities.</param> | ||
| /// <param name="tmpe">Number of non-obsolete TM:PE mods.</param> | ||
| /// | ||
| /// <returns>Returns <c>true</c> if incompatible mods detected, otherwise <c>false</c>.</returns> | ||
| public static bool Verify( | ||
| out Dictionary<PluginInfo, ModDescriptor> results, | ||
| out int minor, | ||
| out int major, | ||
| out int critical, | ||
| out int tmpe) { | ||
|
|
||
| results = new Dictionary<PluginInfo, ModDescriptor>(); | ||
|
|
||
| // current verification state | ||
| bool verified = true; | ||
|
|
||
| // check minor severity incompatibilities? | ||
| bool scanMinor = GlobalConfig.Instance.Main.ScanForKnownIncompatibleModsAtStartup; | ||
|
|
||
| // check disabled mods? note: Critical incompatibilities are always processed | ||
| bool scanDisabled = !GlobalConfig.Instance.Main.IgnoreDisabledMods; | ||
|
|
||
| // batch all logging in to a single log message | ||
| // 6000 chars is roughly 120 mods worth of logging | ||
| StringBuilder log = new StringBuilder(6000); | ||
|
|
||
| log.AppendFormat( | ||
| "Compatibility.Check.Mods.Verify() scanMinor={0}, scanDisabled={1}\n\n", | ||
| scanMinor, | ||
| scanDisabled); | ||
|
|
||
| // Variables for log file entries | ||
| string logWorkshopId; | ||
| string logIncompatible; | ||
|
|
||
| // problem counters | ||
| minor = major = critical = tmpe = 0; | ||
|
|
||
| PluginManager manager = Singleton<PluginManager>.instance; | ||
|
|
||
| List<PluginInfo> mods = new List<PluginInfo>(manager.modCount); | ||
|
|
||
| mods.AddRange(manager.GetPluginsInfo()); // normal mods | ||
| mods.AddRange(manager.GetCameraPluginInfos()); // camera scripts | ||
|
|
||
| // iterate plugins | ||
| foreach (PluginInfo mod in mods) { | ||
|
|
||
| try { | ||
| // Generate descriptor for the mod | ||
| ModDescriptor descriptor = mod; | ||
|
|
||
| // String to log for workshop id | ||
| logWorkshopId = mod.isBuiltin | ||
| ? BUNDLED_MOD_STR | ||
| : descriptor.ModIsLocal | ||
| ? LOCAL_MOD_STR | ||
| : descriptor.ModWorkshopId.ToString(); | ||
|
|
||
| switch (descriptor.Incompatibility) { | ||
|
|
||
| case Severity.Critical: | ||
| logIncompatible = MARKER_CRITICAL; | ||
| verified = false; | ||
| ++critical; | ||
| results.Add(mod, descriptor); | ||
| break; | ||
|
|
||
| case Severity.Major: | ||
| logIncompatible = MARKER_MAJOR; | ||
| if (mod.isEnabled || scanDisabled) { | ||
| verified = false; | ||
| ++major; | ||
| results.Add(mod, descriptor); | ||
| } | ||
| break; | ||
|
|
||
| case Severity.Minor: | ||
| logIncompatible = MARKER_MINOR; | ||
| if (scanMinor && (mod.isEnabled || scanDisabled)) { | ||
| verified = false; | ||
| ++minor; | ||
| results.Add(mod, descriptor); | ||
| } | ||
| break; | ||
|
|
||
| case Severity.TMPE: | ||
| logIncompatible = MARKER_TMPE; | ||
| ++tmpe; | ||
| if (descriptor.AssemblyGuid != CompatibilityManager.SelfGuid) { | ||
| verified = false; | ||
| results.Add(mod, descriptor); | ||
| } | ||
| break; | ||
|
|
||
| default: | ||
| case Severity.None: | ||
| logIncompatible = MARKER_BLANK; | ||
| break; | ||
| } | ||
|
|
||
| log.AppendFormat( | ||
| LOG_ENTRY_FORMAT, | ||
| logIncompatible, | ||
| mod.isEnabled ? MARKER_ENABLED : MARKER_BLANK, | ||
| logWorkshopId.PadRight(12), | ||
| descriptor.ModName); | ||
|
|
||
| } catch (Exception e) { | ||
| Log.ErrorFormat( | ||
| "Error scanning {0}:\n{1}", | ||
| mod.modPath, | ||
| e.ToString()); | ||
| } | ||
|
|
||
| } // foreach | ||
|
|
||
| log.AppendFormat( | ||
| "\n{0} Mod(s), *{1} enabled: {2} [C]ritical, {3} [M]ajor, {4} [m]inor, {5} > TM:PE\n", | ||
| manager.modCount, | ||
| manager.enabledModCount, | ||
| critical, | ||
| major, | ||
| minor, | ||
| tmpe); | ||
|
|
||
| Log.Info(log.ToString()); | ||
|
|
||
| return verified; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| namespace TrafficManager.Compatibility.Check { | ||
| using CSUtil.Commons; | ||
| using System; | ||
|
|
||
| /// <summary> | ||
| /// Checks version equality with added logging. | ||
| /// </summary> | ||
| public class Versions { | ||
|
|
||
| /// <summary> | ||
| /// Verifies that expected version matches actual verison. | ||
| /// | ||
| /// Versions are matched on Major.minor.build. Revision is ignored. | ||
| /// </summary> | ||
| /// | ||
| /// <param name="expected">The version you are expecting.</param> | ||
| /// <param name="actual">The actual version.</param> | ||
| /// | ||
| /// <returns>Returns <c>true</c> if versions match, otherwise <c>false</c>.</returns> | ||
| public static bool Verify(Version expected, Version actual) { | ||
| Log.InfoFormat( | ||
| "Compatibility.Check.Versions.Verify({0}, {1})", | ||
| expected.ToString(3), | ||
| actual.ToString(3)); | ||
|
|
||
| return expected == actual; | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.