Skip to content
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

Lifecycle part 1 - IUserMod #773

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions TLM/TLM/Lifecycle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
namespace TrafficManager {
using CSUtil.Commons;
using ICities;
using TrafficManager.State;
using TrafficManager.UI;

/// <summary>
/// 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.
/// </summary>
public class Lifecycle { // : ILifecycle

/// <summary>
/// The Lifecycle instance; may be <c>null</c>.
/// </summary>
private static Lifecycle instance_;

/// <summary>
/// Gets the <see cref="Lifecycle"/> instance (creates one if necessary).
/// </summary>
public static Lifecycle Instance => instance_ ?? (instance_ = new Lifecycle());

/// <summary>
/// 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.
/// </summary>
///
/// <param name="hotLoad">If <c>true</c>, the mod was enabled due to hot reload.</param>
public void OnEnabled(bool hotLoad) {
if (hotLoad) {
Log.Info("HOT RELOAD");
} else {
Temp.LogEnvironmentDetails();
}
}

/// <summary>
/// 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.
/// </summary>
///
/// <param name="locale">A string representing the language code.</param>
public void OnLocaleChange(string locale) {
Translation.HandleGameLocaleChange();
}

/// <summary>
/// Called when the game wants the mod to create its settings UI:
///
/// * When mod is first enabled
/// * Each time a city is loaded.
///
/// The <paramref name="inGame"/> parameter can be used to adapt your settings
/// screen depending on whether it's in-game or not.
/// </summary>
///
/// <param name="helper">The <see cref="UIHelperBase"/> instance used to create the UI.</param>
/// <param name="inGame">If <c>true</c>, the in-game settings screen should be created.</param>
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?
Options.MakeSettings(helper);
}

/// <summary>
/// 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.
/// </summary>
///
/// <returns>Return <c>true</c> if environment is compatible, otherwise <c>false</c>.</returns>
public bool OnCompatibilityCheck() {
// todo: should we pass in game version as a `Version`?
return Temp.CheckCompatibility();
}

/// <summary>
/// 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.
/// </summary>
///
/// <param name="hotUnload">If <c>true</c>, the mod was enabled due to hot reload.</param>
public void OnDisabled(bool hotUnload) {
Log.Info("TM:PE disabled.");
}

}
}
6 changes: 4 additions & 2 deletions TLM/TLM/TLM.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
Expand Down Expand Up @@ -143,12 +143,14 @@
<Compile Include="Custom\AI\CustomVehicleAI.cs" />
<Compile Include="Custom\Data\CustomVehicle.cs" />
<Compile Include="Geometry\Impl\SegmentEndId.cs" />
<Compile Include="Lifecycle.cs" />
<Compile Include="Manager\AbstractCustomManager.cs" />
<Compile Include="Manager\AbstractFeatureManager.cs" />
<Compile Include="Manager\AbstractGeometryObservingManager.cs" />
<Compile Include="Manager\Impl\ExtNodeManager.cs" />
<Compile Include="Manager\Impl\ExtSegmentEndManager.cs" />
<Compile Include="Manager\Impl\ExtSegmentManager.cs" />
<Compile Include="Temp.cs" />
<Compile Include="UI\Helpers\NodeLaneMarker.cs" />
<Compile Include="UI\Helpers\SegmentLaneMarker.cs" />
<Compile Include="UI\Helpers\ExtUITabStrip.cs" />
Expand Down Expand Up @@ -525,7 +527,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Traffic\Data\" />
<Folder Include="U\MainMenu" />
<Folder Include="U\MainMenu\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\TrafficLights\pedestrian_mode_1.png" />
Expand Down
75 changes: 75 additions & 0 deletions TLM/TLM/Temp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
namespace TrafficManager {
using CSUtil.Commons;
using System;
using System.Reflection;
using TrafficManager.Util;

/// <summary>
/// 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.
/// </summary>
public class Temp {

/// <summary>
/// Logs some info about TMPE build, mono version, etc.
/// </summary>
public static void LogEnvironmentDetails() {
LogBuildDetails();
LogTmpeGuid();
LogMonoVersion();
}

/// <summary>
/// Log TMPE build info and what game ver it expects.
/// </summary>
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);
}

/// <summary>
/// Log TMPE Guid.
/// </summary>
public static void LogTmpeGuid() {
Log.InfoFormat(
"Enabled TM:PE has GUID {0}",
Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId);
}

/// <summary>
/// Log Mono version.
/// </summary>
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));
}
}
}

/// <summary>
/// Run compatibility checker.
/// </summary>
///
/// <returns>Returns <c>false</c> if issues found, otherwise <c>true</c>.</returns>
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)
}

}
}
76 changes: 33 additions & 43 deletions TLM/TLM/TrafficManagerMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}
6 changes: 0 additions & 6 deletions TLM/TLM/UI/Localization/Translation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,6 @@ public class Translation {
public static Localization.LookupTable AICar =>
LoadingExtension.TranslationDatabase.aiCarLookup_;

/// <summary>
/// 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 <see cref="TrafficManagerMod.OnSettingsUI"/> and unhooked in <see cref="TrafficManagerMod.OnDisabled"/>.
/// </summary>
public static bool IsListeningToGameLocaleChanged { get; set; } = false;

/// <summary>
/// Gets or sets a value indicating the current lanugage to use for translations.
/// Note: Don't access directly, instead use <see cref="GetCurrentLanguage()"/>.
Expand Down