Decompiled source of CityEditorSaveFix v1.0.1

plugins/CityEditorSaveFix/SoDCityEditorSaveFix.dll

Decompiled an hour ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppSystem.IO;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SoDCityEditorSaveFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("SoDCityEditorSaveFix")]
[assembly: AssemblyTitle("SoDCityEditorSaveFix")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 SoDCityEditorSaveFix
{
	[BepInPlugin("sm3gm.sod.cityeditorsavefix", "City Editor Save Fix", "1.0.1")]
	public sealed class Plugin : BasePlugin
	{
		public const string VER = "1.0.1";

		internal static ManualLogSource L;

		public override void Load()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			L = ((BasePlugin)this).Log;
			Harmony val = new Harmony("sm3gm.sod.cityeditorsavefix");
			val.PatchAll(typeof(GetCityFilePatch));
			val.PatchAll(typeof(CityDataNamePatch));
			val.PatchAll(typeof(SaveNamePatch));
			ManualLogSource l = L;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(28, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("City Editor Save Fix ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.1");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded");
			}
			l.LogInfo(val2);
		}
	}
	internal static class Cities
	{
		internal const string Editor = "CityEditor";

		internal static string? Current;

		internal static string Dir => Path.Combine(Application.persistentDataPath, "Cities");

		internal static bool Exists(string name)
		{
			try
			{
				return Directory.Exists(Dir) && Directory.GetFiles(Dir, name + ".*.CityEditor.cit").Length != 0;
			}
			catch
			{
				return false;
			}
		}

		internal static string CityName(string fileName)
		{
			string[] array = fileName.Split('.');
			if (array.Length >= 5)
			{
				return string.Join(".", array, 0, array.Length - 4);
			}
			return "";
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class CityDataNamePatch
	{
		private static void Prefix(ref CitySaveData cityData)
		{
			try
			{
				if (cityData != null && cityData.seed == "CityEditor" && !string.IsNullOrEmpty(cityData.cityName))
				{
					Cities.Current = cityData.cityName;
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Toolbox), "GetShareCode", new Type[]
	{
		typeof(string),
		typeof(int),
		typeof(int),
		typeof(string),
		typeof(string)
	})]
	internal static class SaveNamePatch
	{
		private static void Prefix(ref string cityName, string seed)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			string current = Cities.Current;
			if (!(seed != "CityEditor") && current != null && !(cityName == current) && !string.IsNullOrEmpty(cityName) && !Cities.Exists(cityName) && Cities.Exists(current))
			{
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(69, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Game was about to store city '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(cityName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'; storing city editor city '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(current);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' instead.");
				}
				l.LogInfo(val);
				cityName = current;
			}
		}
	}
	[HarmonyPatch(typeof(Toolbox), "GetCityFile", new Type[]
	{
		typeof(string),
		typeof(string),
		typeof(int),
		typeof(int),
		typeof(string)
	})]
	internal static class GetCityFilePatch
	{
		private static bool busy;

		private static void Postfix(Toolbox __instance, string codeName, string codeSeed, int codeSizeX, int codeSizeY, string codeVersion, ref FileInfo __result)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			if (busy || codeSeed != "CityEditor" || string.IsNullOrEmpty(codeName))
			{
				return;
			}
			if (__result != null)
			{
				Cities.Current = codeName;
				return;
			}
			try
			{
				if (!Directory.Exists(Cities.Dir))
				{
					return;
				}
				string text = ByName(codeName);
				string text2 = "its name is part of the stored name";
				if (text == null)
				{
					text = ByTime(codeName);
					text2 = "it was the city editor city saved last before this save";
				}
				bool flag = default(bool);
				if (text == null)
				{
					ManualLogSource l = Plugin.L;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(33, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No city editor city found for '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(codeName);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'.");
					}
					l.LogWarning(val);
					return;
				}
				busy = true;
				FileInfo cityFile = __instance.GetCityFile(text, codeSeed, codeSizeX, codeSizeY, codeVersion);
				if (cityFile != null)
				{
					__result = cityFile;
					Cities.Current = text;
					ManualLogSource l2 = Plugin.L;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(64, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Save pointed to city '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(codeName);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("'; loading city editor city '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' instead (");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text2);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(").");
					}
					l2.LogInfo(val2);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("Could not look for the city file: " + ex.Message));
			}
			finally
			{
				busy = false;
			}
		}

		private static string? ByName(string codeName)
		{
			string text = null;
			string[] files = Directory.GetFiles(Cities.Dir, "*.CityEditor.cit");
			for (int i = 0; i < files.Length; i++)
			{
				string text2 = Cities.CityName(Path.GetFileName(files[i]));
				if (text2.Length != 0 && !(text2 == codeName) && ContainsWord(codeName, text2) && (text == null || text2.Length > text.Length))
				{
					text = text2;
				}
			}
			return text;
		}

		private static string? ByTime(string codeName)
		{
			string path = Path.Combine(Application.persistentDataPath, "Save", codeName + ".sod");
			if (!File.Exists(path))
			{
				return null;
			}
			DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(path);
			string result = null;
			DateTime dateTime = DateTime.MinValue;
			string[] files = Directory.GetFiles(Cities.Dir, "*.CityEditor.cit");
			foreach (string path2 in files)
			{
				DateTime lastWriteTimeUtc2 = File.GetLastWriteTimeUtc(path2);
				string text = Cities.CityName(Path.GetFileName(path2));
				if (text.Length != 0 && !(text == codeName) && !(lastWriteTimeUtc2 > lastWriteTimeUtc) && !(lastWriteTimeUtc2 <= dateTime))
				{
					result = text;
					dateTime = lastWriteTimeUtc2;
				}
			}
			return result;
		}

		private static bool ContainsWord(string text, string word)
		{
			for (int num = text.IndexOf(word, StringComparison.Ordinal); num >= 0; num = text.IndexOf(word, num + 1, StringComparison.Ordinal))
			{
				bool num2 = num == 0 || text[num - 1] == ' ';
				int num3 = num + word.Length;
				if (num2 && (num3 == text.Length || text[num3] == ' '))
				{
					return true;
				}
			}
			return false;
		}
	}
}