using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using Colossal.Logging;
using Game;
using Game.Modding;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Collections.Generic;
using MonoMod.Utils;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PDXModsBridge")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+6db79e57f3b1cc3a953d26b72f879adbda474500")]
[assembly: AssemblyProduct("PDXModsBridge")]
[assembly: AssemblyTitle("PDXModsBridge")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace PDXModsBridge
{
internal static class ModLoader
{
private static char _S = Path.DirectorySeparatorChar;
private static string GAME_PATH = Path.GetDirectoryName(Application.dataPath);
private static string BEPINEX_PATH = Path.Combine(GAME_PATH, $"BepInEx{_S}plugins");
private static string THUNDERSTORE_PATH = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), $"AppData{_S}Roaming{_S}Thunderstore Mod Manager{_S}DataFolder{_S}CitiesSkylines2{_S}profiles");
private static string RMODMAN_PATH = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), $"AppData{_S}Roaming{_S}r2modmanPlus-local{_S}CitiesSkylines2{_S}profiles");
private static ILog _logger = LogManager.GetLogger("Cities2Modding");
private static Dictionary<string, List<IMod>> _loadedMods = new Dictionary<string, List<IMod>>();
public static void ScanDirectory()
{
try
{
if (Directory.Exists(BEPINEX_PATH))
{
_logger.Info((object)"[PDXModsBridge] Scanning BepInEx folder...");
ProcessSource(BEPINEX_PATH);
}
string activeThunderstoreProfile = GetActiveThunderstoreProfile();
if (!string.IsNullOrEmpty(activeThunderstoreProfile))
{
_logger.Info((object)("[PDXModsBridge] Scanning Thunderstore folder '" + activeThunderstoreProfile + "'..."));
ProcessSource(activeThunderstoreProfile);
}
string activeRModManProfile = GetActiveRModManProfile();
if (!string.IsNullOrEmpty(activeRModManProfile))
{
_logger.Info((object)("[PDXModsBridge] Scanning rModMan folder '" + activeRModManProfile + "'..."));
ProcessSource(activeRModManProfile);
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
private static void ProcessSource(string sourceDirectory)
{
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Expected O, but got Unknown
string[] files = Directory.GetFiles(sourceDirectory, "*.dll", SearchOption.AllDirectories);
string[] array = files;
foreach (string text in array)
{
try
{
Dictionary<string, List<IMod>> loadedMods = _loadedMods;
if (loadedMods != null && loadedMods.ContainsKey(text))
{
continue;
}
AssemblyDefinition val = AssemblyDefinition.ReadAssembly(text, TypeLoader.ReaderParameters);
List<IMod> list = new List<IMod>();
List<Type> list2 = (from t in ((IEnumerable<TypeDefinition>)val.MainModule.Types).Where(delegate(TypeDefinition t)
{
int result;
if (t != null && t.HasInterfaces)
{
Collection<InterfaceImplementation> interfaces = t.Interfaces;
result = ((interfaces != null && ((IEnumerable<InterfaceImplementation>)interfaces).Count(delegate(InterfaceImplementation i)
{
TypeReference interfaceType = i.InterfaceType;
return ((interfaceType != null) ? ((MemberReference)interfaceType).FullName : null) == typeof(IMod).FullName;
}) > 0) ? 1 : 0);
}
else
{
result = 0;
}
return (byte)result != 0;
})
select ReflectionHelper.ResolveReflection((TypeReference)(object)t)).Distinct().ToList();
if (list2 != null && list2.Count > 0)
{
foreach (Type item in list2)
{
if (item == null)
{
continue;
}
DescriptionAttribute customAttribute = item.GetCustomAttribute<DescriptionAttribute>();
if (customAttribute != null && !string.IsNullOrEmpty(customAttribute.Description) && !(customAttribute.Description.ToLowerInvariant() != "bridge"))
{
IMod val2 = (IMod)Activator.CreateInstance(item);
if (val2 != null)
{
list.Add(val2);
_logger.Info((object)("[PDXModsBridge] Initialised IMod from third-party mod sources: '" + item.FullName + "'."));
Debug.Log((object)("[PDXModsBridge] Initialised IMod from third-party mod sources: '" + item.FullName + "'."));
}
}
}
if (list.Count == 0)
{
_logger.Debug((object)("[PDXModsBridge] No mods to load in '" + text + "'."));
}
}
_loadedMods[text] = list;
val.Dispose();
}
catch (BadImageFormatException ex)
{
_logger.Debug((object)("Invalid .NET assembly, skipping " + text + ": " + ex.Message));
}
catch (Exception ex2)
{
_logger.Error((object)ex2.ToString());
}
}
}
private static string GetActiveProfile(string path)
{
if (!Directory.Exists(path))
{
return null;
}
DateTime dateTime = DateTime.MinValue;
string result = string.Empty;
string[] directories = Directory.GetDirectories(path);
foreach (string path2 in directories)
{
string text = Path.Combine(path2, $"BepInEx{_S}plugins");
if (Directory.Exists(text))
{
DateTime mostRecentModifiedDate = GetMostRecentModifiedDate(text);
if (mostRecentModifiedDate > dateTime)
{
dateTime = mostRecentModifiedDate;
result = text;
}
}
}
return result;
}
public static DateTime GetMostRecentModifiedDate(string directory)
{
return (from file in Directory.GetFiles(directory, "*", SearchOption.AllDirectories)
select new FileInfo(file).LastWriteTime into date
orderby date descending
select date).FirstOrDefault();
}
private static string GetActiveThunderstoreProfile()
{
return GetActiveProfile(THUNDERSTORE_PATH);
}
private static string GetActiveRModManProfile()
{
if (Directory.Exists(RMODMAN_PATH))
{
return GetActiveProfile(RMODMAN_PATH);
}
string environmentVariable = Environment.GetEnvironmentVariable("DOORSTOP_INVOKE_DLL_PATH");
string directoryName = Path.GetDirectoryName(environmentVariable);
string fullPath = Path.GetFullPath(Path.Combine(directoryName, "..", "..", ".."));
return GetActiveProfile(fullPath);
}
private static void HandleException(Exception ex)
{
if (ex is IOException || ex is UnauthorizedAccessException || ex is SecurityException || ex is InvalidDataException || ex is FileNotFoundException)
{
_logger.Error(ex);
return;
}
throw ex;
}
public static void Load(UpdateSystem updateSystem)
{
if (_loadedMods == null || _loadedMods.Count == 0)
{
return;
}
foreach (KeyValuePair<string, List<IMod>> loadedMod in _loadedMods)
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(loadedMod.Key);
List<IMod> value = loadedMod.Value;
if (!value.Any())
{
continue;
}
foreach (IMod item in value)
{
item.OnLoad(updateSystem);
_logger.Info((object)("[PDXModsBridge] On load '" + fileNameWithoutExtension + "' ."));
}
}
}
public static void Unload()
{
if (_loadedMods == null || _loadedMods.Count == 0)
{
return;
}
foreach (KeyValuePair<string, List<IMod>> loadedMod in _loadedMods)
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(loadedMod.Key);
List<IMod> value = loadedMod.Value;
if (!value.Any())
{
continue;
}
foreach (IMod item in value)
{
item.OnDispose();
_logger.Info((object)("[PDXModsBridge] Unloaded mod '" + fileNameWithoutExtension + "'."));
}
}
}
}
[BepInPlugin("PDXModsBridge", "PDXModsBridge", "1.1.0")]
public class Plugin : BaseUnityPlugin
{
private static Harmony _harmony;
private void Awake()
{
_harmony = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "PDXModsBridge_Cities2Harmony");
MethodBase[] array = _harmony.GetPatchedMethods().ToArray();
((BaseUnityPlugin)this).Logger.LogInfo((object)"=================================================================");
((BaseUnityPlugin)this).Logger.LogInfo((object)"PDXModsBridge by Cities2Modding community.");
((BaseUnityPlugin)this).Logger.LogInfo((object)"=================================================================");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Reddit link: https://www.reddit.com/r/cities2modding/");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Discord link: https://discord.gg/KGRNBbm5Fh");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Our mods are officially distributed via Thunderstore.io and https://github.com/Cities2Modding");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Example mod repository and modding info: https://github.com/optimus-code/Cities2Modding");
((BaseUnityPlugin)this).Logger.LogInfo((object)"Thanks to 89pleasure, Rebecca, optimus-code and the Cites2Modding community!");
((BaseUnityPlugin)this).Logger.LogInfo((object)"=================================================================");
((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin PDXModsBridge is loaded! Patched methods: " + array.Length));
MethodBase[] array2 = array;
foreach (MethodBase methodBase in array2)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched method: " + methodBase.Module.Name + ":" + methodBase.Name));
}
ModLoader.ScanDirectory();
}
private void OnDestroy()
{
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "PDXModsBridge";
public const string PLUGIN_NAME = "PDXModsBridge";
public const string PLUGIN_VERSION = "1.1.0";
}
}
namespace PDXModsBridge.Patches
{
[HarmonyPatch(typeof(ModManager), "InitializeMods")]
internal static class InitializeMods_Patch
{
private static void Postfix(UpdateSystem updateSystem)
{
ModLoader.Load(updateSystem);
}
}
}