diff --git a/TLM/TLM/Lifecycle.cs b/TLM/TLM/Lifecycle.cs
new file mode 100644
index 000000000..eeae5fc60
--- /dev/null
+++ b/TLM/TLM/Lifecycle.cs
@@ -0,0 +1,112 @@
+namespace TrafficManager {
+ using CSUtil.Commons;
+ using ICities;
+ using TrafficManager.State;
+ using TrafficManager.UI;
+
+ ///
+ /// This class manages the lifecycle of TMPE mod.
+ ///
+ /// It also serves as an initial design draft for HarmonyLifecycle mod.
+ /// Code commenting is verbose; that would get moved to docs somwhere.
+ ///
+ public class Lifecycle { // : ILifecycle
+
+ ///
+ /// The Lifecycle instance; may be null.
+ ///
+ private static Lifecycle instance_;
+
+ ///
+ /// Gets the instance (creates one if necessary).
+ ///
+ public static Lifecycle Instance => instance_ ?? (instance_ = new Lifecycle());
+
+ ///
+ /// Called when the mod is enabled in one of the following ways:
+ ///
+ /// * Manually in Content Manager > Mods
+ /// * Already enabled when Cities.exe starts
+ /// * Auto-enabled upon subscription, by the Mod Autoenabler mod
+ /// * Hot reload of a dev build.
+ ///
+ ///
+ /// If true, the mod was enabled due to hot reload.
+ public void OnEnabled(bool hotLoad) {
+ if (hotLoad) {
+ Log.Info("HOT RELOAD");
+ } else {
+ Temp.LogEnvironmentDetails();
+ }
+ }
+
+ ///
+ /// Called when locale needs updating:
+ ///
+ /// * Before OnSettings(), if not already called
+ /// * When user changes game language.
+ ///
+ /// Note that lanauge mods often use non-standard language codes such as:
+ ///
+ /// * jaex --> ja
+ /// * zh-cn --> zh
+ /// * kr --> ko.
+ ///
+ ///
+ /// A string representing the language code.
+ public void OnLocaleChange(string locale) {
+ Translation.HandleGameLocaleChange();
+ }
+
+ ///
+ /// Called when the game wants the mod to create its settings UI:
+ ///
+ /// * When mod is first enabled
+ /// * Each time a city is loaded.
+ ///
+ /// The parameter can be used to adapt your settings
+ /// screen depending on whether it's in-game or not.
+ ///
+ ///
+ /// The instance used to create the UI.
+ /// If true, the in-game settings screen should be created.
+ public void OnSettings(UIHelperBase helper, bool inGame) {
+ // todo: instead of `inGame` bool, should we use an enum (or whatever) to
+ // differentiate between in-game, in scneario, in editor, etc?
+ // or have separate methods, eg. OnMainSettings(), OnGameSettings(), OnEditorSettings()?
+ Options.MakeSettings(helper);
+ }
+
+ ///
+ /// Called at an appropriate time to perform compatibility checks:
+ ///
+ /// * PluginManager has processed all mods
+ /// * Intro screens have completed; UIView is available
+ /// * App localisation services are available
+ /// * NOT loading, unloading or exiting
+ /// * NOT in game or editor.
+ ///
+ ///
+ /// Return true if environment is compatible, otherwise false.
+ public bool OnCompatibilityCheck() {
+ // todo: should we pass in game version as a `Version`?
+ return Temp.CheckCompatibility();
+ }
+
+
+ ///
+ /// Called when the mod is disabled in one of the following ways:
+ ///
+ /// * Manually in Content Manager > Mods
+ /// * Unsubscribed while enabled
+ /// * Hot reload of dev build causes hot unload of current build
+ /// * Game exit to desktop.
+ ///
+ ///
+ /// If true, the mod was enabled due to hot reload.
+ public void OnDisabled(bool hotUnload) {
+ Log.Info("TM:PE disabled.");
+ }
+
+ }
+}
diff --git a/TLM/TLM/LoadingExtension.cs b/TLM/TLM/LoadingExtension.cs
index cb7c9e4bb..9e5e36139 100644
--- a/TLM/TLM/LoadingExtension.cs
+++ b/TLM/TLM/LoadingExtension.cs
@@ -392,72 +392,7 @@ public override void OnLevelLoaded(LoadMode mode) {
case SimulationManager.UpdateMode.NewGameFromMap:
case SimulationManager.UpdateMode.NewGameFromScenario:
case SimulationManager.UpdateMode.LoadGame: {
- if (BuildConfig.applicationVersion != BuildConfig.VersionToString(
- TrafficManagerMod.GAME_VERSION,
- false))
- {
- string[] majorVersionElms = BuildConfig.applicationVersion.Split('-');
- string[] versionElms = majorVersionElms[0].Split('.');
- uint versionA = Convert.ToUInt32(versionElms[0]);
- uint versionB = Convert.ToUInt32(versionElms[1]);
- uint versionC = Convert.ToUInt32(versionElms[2]);
-
- Log.Info($"Detected game version v{BuildConfig.applicationVersion}");
-
- bool isModTooOld = TrafficManagerMod.GAME_VERSION_A < versionA ||
- (TrafficManagerMod.GAME_VERSION_A == versionA &&
- TrafficManagerMod.GAME_VERSION_B < versionB);
- // || (TrafficManagerMod.GameVersionA == versionA
- // && TrafficManagerMod.GameVersionB == versionB
- // && TrafficManagerMod.GameVersionC < versionC);
-
- bool isModNewer = TrafficManagerMod.GAME_VERSION_A < versionA ||
- (TrafficManagerMod.GAME_VERSION_A == versionA &&
- TrafficManagerMod.GAME_VERSION_B > versionB);
- // || (TrafficManagerMod.GameVersionA == versionA
- // && TrafficManagerMod.GameVersionB == versionB
- // && TrafficManagerMod.GameVersionC > versionC);
-
- if (isModTooOld) {
- string msg = string.Format(
- "Traffic Manager: President Edition detected that you are running " +
- "a newer game version ({0}) than TM:PE has been built for ({1}). " +
- "Please be aware that TM:PE has not been updated for the newest game " +
- "version yet and thus it is very likely it will not work as expected.",
- BuildConfig.applicationVersion,
- BuildConfig.VersionToString(TrafficManagerMod.GAME_VERSION, false));
-
- Log.Error(msg);
- Singleton.instance.m_ThreadingWrapper.QueueMainThread(
- () => {
- UIView.library
- .ShowModal("ExceptionPanel")
- .SetMessage(
- "TM:PE has not been updated yet",
- msg,
- false);
- });
- } else if (isModNewer) {
- string msg = string.Format(
- "Traffic Manager: President Edition has been built for game version {0}. " +
- "You are running game version {1}. Some features of TM:PE will not " +
- "work with older game versions. Please let Steam update your game.",
- BuildConfig.VersionToString(TrafficManagerMod.GAME_VERSION, false),
- BuildConfig.applicationVersion);
-
- Log.Error(msg);
- Singleton
- .instance.m_ThreadingWrapper.QueueMainThread(
- () => {
- UIView.library
- .ShowModal("ExceptionPanel")
- .SetMessage(
- "Your game should be updated",
- msg,
- false);
- });
- }
- }
+ Temp.CheckGameVersion();
IsGameLoaded = true;
break;
diff --git a/TLM/TLM/TLM.csproj b/TLM/TLM/TLM.csproj
index 396552b8a..dad1e6cfb 100644
--- a/TLM/TLM/TLM.csproj
+++ b/TLM/TLM/TLM.csproj
@@ -1,4 +1,4 @@
-
+
@@ -143,12 +143,14 @@
+
+
@@ -525,7 +527,7 @@
-
+
diff --git a/TLM/TLM/Temp.cs b/TLM/TLM/Temp.cs
new file mode 100644
index 000000000..87c354bc3
--- /dev/null
+++ b/TLM/TLM/Temp.cs
@@ -0,0 +1,150 @@
+namespace TrafficManager {
+ using ColossalFramework;
+ using ColossalFramework.UI;
+ using CSUtil.Commons;
+ using System;
+ using System.Reflection;
+ using TrafficManager.Util;
+
+ ///
+ /// This class is a temporary place to put a bunch of stuff until a better place is found for it.
+ ///
+ /// Much of this stuff will be replaced as part of PR #699.
+ ///
+ public class Temp {
+
+ ///
+ /// Logs some info about TMPE build, mono version, etc.
+ ///
+ public static void LogEnvironmentDetails() {
+ LogBuildDetails();
+ LogTmpeGuid();
+ LogMonoVersion();
+ }
+
+ ///
+ /// Log TMPE build info and what game ver it expects.
+ ///
+ public static void LogBuildDetails() {
+ Log.InfoFormat(
+ "TM:PE enabled. Version {0}, Build {1} {2} for game version {3}.{4}.{5}-f{6}",
+ TrafficManagerMod.VersionString,
+ Assembly.GetExecutingAssembly().GetName().Version,
+ TrafficManagerMod.BRANCH,
+ TrafficManagerMod.GAME_VERSION_A,
+ TrafficManagerMod.GAME_VERSION_B,
+ TrafficManagerMod.GAME_VERSION_C,
+ TrafficManagerMod.GAME_VERSION_BUILD);
+ }
+
+ ///
+ /// Log TMPE Guid.
+ ///
+ public static void LogTmpeGuid() {
+ Log.InfoFormat(
+ "Enabled TM:PE has GUID {0}",
+ Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId);
+ }
+
+ ///
+ /// Log Mono version.
+ ///
+ public static void LogMonoVersion() {
+ // Log Mono version
+ Type monoRt = Type.GetType("Mono.Runtime");
+ if (monoRt != null) {
+ MethodInfo displayName = monoRt.GetMethod(
+ "GetDisplayName",
+ BindingFlags.NonPublic | BindingFlags.Static);
+ if (displayName != null) {
+ Log.InfoFormat("Mono version: {0}", displayName.Invoke(null, null));
+ }
+ }
+ }
+
+ ///
+ /// Run compatibility checker.
+ ///
+ ///
+ /// Returns false if issues found, otherwise true.
+ public static bool CheckCompatibility() {
+ ModsCompatibilityChecker mcc = new ModsCompatibilityChecker();
+ mcc.PerformModCheck();
+ return true; // ideally this would return false if there are compatibility issues (#699 will sort that)
+ }
+
+ ///
+ /// Checks to see if game version is what TMPE expects, and if not warns users.
+ ///
+ /// This will be replaced as part of #699.
+ ///
+ public static void CheckGameVersion() {
+ if (BuildConfig.applicationVersion != BuildConfig.VersionToString(
+ TrafficManagerMod.GAME_VERSION,
+ false)) {
+ string[] majorVersionElms = BuildConfig.applicationVersion.Split('-');
+ string[] versionElms = majorVersionElms[0].Split('.');
+ uint versionA = Convert.ToUInt32(versionElms[0]);
+ uint versionB = Convert.ToUInt32(versionElms[1]);
+ uint versionC = Convert.ToUInt32(versionElms[2]);
+
+ Log.Info($"Detected game version v{BuildConfig.applicationVersion}");
+
+ bool isModTooOld = TrafficManagerMod.GAME_VERSION_A < versionA ||
+ (TrafficManagerMod.GAME_VERSION_A == versionA &&
+ TrafficManagerMod.GAME_VERSION_B < versionB);
+ // || (TrafficManagerMod.GameVersionA == versionA
+ // && TrafficManagerMod.GameVersionB == versionB
+ // && TrafficManagerMod.GameVersionC < versionC);
+
+ bool isModNewer = TrafficManagerMod.GAME_VERSION_A < versionA ||
+ (TrafficManagerMod.GAME_VERSION_A == versionA &&
+ TrafficManagerMod.GAME_VERSION_B > versionB);
+ // || (TrafficManagerMod.GameVersionA == versionA
+ // && TrafficManagerMod.GameVersionB == versionB
+ // && TrafficManagerMod.GameVersionC > versionC);
+
+ if (isModTooOld) {
+ string msg = string.Format(
+ "Traffic Manager: President Edition detected that you are running " +
+ "a newer game version ({0}) than TM:PE has been built for ({1}). " +
+ "Please be aware that TM:PE has not been updated for the newest game " +
+ "version yet and thus it is very likely it will not work as expected.",
+ BuildConfig.applicationVersion,
+ BuildConfig.VersionToString(TrafficManagerMod.GAME_VERSION, false));
+
+ Log.Error(msg);
+ Singleton.instance.m_ThreadingWrapper.QueueMainThread(
+ () => {
+ UIView.library
+ .ShowModal("ExceptionPanel")
+ .SetMessage(
+ "TM:PE has not been updated yet",
+ msg,
+ false);
+ });
+ } else if (isModNewer) {
+ string msg = string.Format(
+ "Traffic Manager: President Edition has been built for game version {0}. " +
+ "You are running game version {1}. Some features of TM:PE will not " +
+ "work with older game versions. Please let Steam update your game.",
+ BuildConfig.VersionToString(TrafficManagerMod.GAME_VERSION, false),
+ BuildConfig.applicationVersion);
+
+ Log.Error(msg);
+ Singleton
+ .instance.m_ThreadingWrapper.QueueMainThread(
+ () => {
+ UIView.library
+ .ShowModal("ExceptionPanel")
+ .SetMessage(
+ "Your game should be updated",
+ msg,
+ false);
+ });
+ }
+ }
+ }
+
+ }
+}
diff --git a/TLM/TLM/TrafficManagerMod.cs b/TLM/TLM/TrafficManagerMod.cs
index a5525ceb8..a7a4412ed 100644
--- a/TLM/TLM/TrafficManagerMod.cs
+++ b/TLM/TLM/TrafficManagerMod.cs
@@ -48,73 +48,63 @@ public class TrafficManagerMod : IUserMod {
internal static bool InGame() => SceneManager.GetActiveScene().name == "Game";
+ internal static bool listeningToLocaleChange_ = false;
+
[UsedImplicitly]
public void OnEnabled() {
- Log.InfoFormat(
- "TM:PE enabled. Version {0}, Build {1} {2} for game version {3}.{4}.{5}-f{6}",
- VersionString,
- Assembly.GetExecutingAssembly().GetName().Version,
- BRANCH,
- GAME_VERSION_A,
- GAME_VERSION_B,
- GAME_VERSION_C,
- GAME_VERSION_BUILD);
- Log.InfoFormat(
- "Enabled TM:PE has GUID {0}",
- Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId);
-
- // check for incompatible mods
- if (UIView.GetAView() != null) {
- // when TM:PE is enabled in content manager
- CheckForIncompatibleMods();
- } else {
- // or when game first loads if TM:PE was already enabled
- LoadingManager.instance.m_introLoaded += CheckForIncompatibleMods;
- }
+ Instance = this;
+ InGameHotReload = InGame();
- // Log Mono version
- Type monoRt = Type.GetType("Mono.Runtime");
- if (monoRt != null) {
- MethodInfo displayName = monoRt.GetMethod(
- "GetDisplayName",
- BindingFlags.NonPublic | BindingFlags.Static);
- if (displayName != null) {
- Log.InfoFormat("Mono version: {0}", displayName.Invoke(null, null));
+ Lifecycle.Instance.OnEnabled(InGameHotReload);
+
+ if (!InGameHotReload) {
+ // check for incompatible mods
+ if (UIView.GetAView() != null) {
+ // when TM:PE is enabled in content manager
+ Lifecycle.Instance.OnCompatibilityCheck();
+ } else {
+ // or when game first loads if TM:PE was already enabled
+ LoadingManager.instance.m_introLoaded += CheckForIncompatibleMods;
}
}
-
- Instance = this;
- InGameHotReload = InGame();
}
[UsedImplicitly]
public void OnDisabled() {
- Log.Info("TM:PE disabled.");
LoadingManager.instance.m_introLoaded -= CheckForIncompatibleMods;
- LocaleManager.eventLocaleChanged -= Translation.HandleGameLocaleChange;
- Translation.IsListeningToGameLocaleChanged = false; // is this necessary?
+ LocaleManager.eventLocaleChanged -= GameLocaleChanged;
- if (InGame() && LoadingExtension.Instance != null) {
+ bool hotUnload = InGame() && LoadingExtension.Instance != null;
+
+ if (hotUnload) {
//Hot reload Unloading
LoadingExtension.Instance.OnLevelUnloading();
LoadingExtension.Instance.OnReleased();
}
+
+ Lifecycle.Instance.OnDisabled(hotUnload);
+
Instance = null;
}
[UsedImplicitly]
public void OnSettingsUI(UIHelperBase helper) {
- // Note: This bugs out if done in OnEnabled(), hence doing it here instead.
- if (!Translation.IsListeningToGameLocaleChanged) {
- Translation.IsListeningToGameLocaleChanged = true;
- LocaleManager.eventLocaleChanged += new LocaleManager.LocaleChangedHandler(Translation.HandleGameLocaleChange);
+ if (!listeningToLocaleChange_) {
+ listeningToLocaleChange_ = true;
+ LocaleManager.eventLocaleChanged += new LocaleManager.LocaleChangedHandler(GameLocaleChanged);
+ GameLocaleChanged(); // call on first use
}
- Options.MakeSettings(helper);
+
+ Lifecycle.Instance.OnSettings(helper, InGame());
+ }
+
+ private static void GameLocaleChanged() {
+ Lifecycle.Instance.OnLocaleChange(LocaleManager.instance.language);
}
private static void CheckForIncompatibleMods() {
- ModsCompatibilityChecker mcc = new ModsCompatibilityChecker();
- mcc.PerformModCheck();
+ LoadingManager.instance.m_introLoaded -= CheckForIncompatibleMods;
+ Lifecycle.Instance.OnCompatibilityCheck();
}
}
}
diff --git a/TLM/TLM/UI/Localization/Translation.cs b/TLM/TLM/UI/Localization/Translation.cs
index ba72f8c9a..a91f36dc5 100644
--- a/TLM/TLM/UI/Localization/Translation.cs
+++ b/TLM/TLM/UI/Localization/Translation.cs
@@ -98,12 +98,6 @@ public class Translation {
public static Localization.LookupTable AICar =>
LoadingExtension.TranslationDatabase.aiCarLookup_;
- ///
- /// Gets or sets a value indicating whether we're currently listening to the event fired when user changes game langauge.
- /// The event is hooked in and unhooked in .
- ///
- public static bool IsListeningToGameLocaleChanged { get; set; } = false;
-
///
/// Gets or sets a value indicating the current lanugage to use for translations.
/// Note: Don't access directly, instead use .