Decompiled source of BirthdayPack v1.5.0

plugins/BirthdayPhotos.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BirthdayPhotos")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("BirthdayPhotos")]
[assembly: AssemblyTitle("BirthdayPhotos")]
[assembly: AssemblyVersion("1.2.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 BirthdayPhotos
{
	internal static class MaterialSwapper
	{
		private static readonly string[] TextureProps = new string[2] { "_BaseColorMap", "_MainTex" };

		private static readonly string[] ColorProps = new string[2] { "_BaseColor", "_Color" };

		private static readonly Dictionary<string, Material> Copies = new Dictionary<string, Material>();

		private static readonly HashSet<int> OurMaterials = new HashSet<int>();

		private static readonly HashSet<int> LoggedObjects = new HashSet<int>();

		private static int radarLayer = -2;

		public static void ApplyNextFrame(MonoBehaviour owner, Action apply)
		{
			try
			{
				owner.StartCoroutine(NextFrame(apply));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Не удалось запланировать замену для {((owner != null) ? ((Object)owner).name : null)}: {arg}");
			}
		}

		private static IEnumerator NextFrame(Action apply)
		{
			yield return null;
			Safe(apply);
		}

		public static void Safe(Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Ошибка замены текстуры: {arg}");
			}
		}

		public static void ApplyEnemy(EnemyAI enemy)
		{
			if (!((Object)(object)enemy == (Object)null))
			{
				string name = (((Object)(object)enemy.enemyType != (Object)null) ? enemy.enemyType.enemyName : ((Object)((Component)enemy).gameObject).name);
				IEnumerable<Renderer> renderers = from r in Renderers(((Component)enemy).gameObject)
					where (Object)(object)((Component)r).GetComponentInParent<GrabbableObject>(true) == (Object)null && (Object)(object)((Component)r).GetComponentInParent<PlayerControllerB>(true) == (Object)null
					select r;
				Apply((Component)(object)enemy, "Монстр", name, renderers, Plugin.MainPhotos, 0uL);
			}
		}

		public static void ApplyItem(GrabbableObject item)
		{
			if (!((Object)(object)item == (Object)null) && !((Object)(object)item.itemProperties == (Object)null))
			{
				IEnumerable<Renderer> renderers = from r in Renderers(((Component)item).gameObject)
					where (Object)(object)((Component)r).GetComponentInParent<GrabbableObject>(true) == (Object)(object)item
					select r;
				Apply((Component)(object)item, "Лут", item.itemProperties.itemName, renderers, Plugin.MainPhotos, 0uL);
			}
		}

		public static void ApplyStoreItem(GrabbableObject item)
		{
			if (!((Object)(object)item == (Object)null) && !((Object)(object)item.itemProperties == (Object)null))
			{
				IEnumerable<Renderer> renderers = from r in Renderers(((Component)item).gameObject)
					where (Object)(object)((Component)r).GetComponentInParent<GrabbableObject>(true) == (Object)(object)item
					select r;
				ulong salt = (((NetworkBehaviour)item).IsSpawned ? (((NetworkBehaviour)item).NetworkObjectId + 1) : 0);
				Apply((Component)(object)item, "Предмет", item.itemProperties.itemName, renderers, Plugin.StorePhotos, salt);
			}
		}

		private static IEnumerable<Renderer> Renderers(GameObject root)
		{
			if (radarLayer == -2)
			{
				radarLayer = LayerMask.NameToLayer("MapRadar");
			}
			return from r in root.GetComponentsInChildren<Renderer>(true)
				where (r is MeshRenderer || r is SkinnedMeshRenderer) && ((Component)r).gameObject.layer != radarLayer
				select r;
		}

		private static void Apply(Component target, string kind, string name, IEnumerable<Renderer> renderers, PhotoLibrary library, ulong salt)
		{
			string reason;
			Photo photo = library.Choose(name, out reason, salt);
			bool flag = LoggedObjects.Add(((Object)target).GetInstanceID());
			if (photo == null)
			{
				if (flag)
				{
					Plugin.Log.LogWarning((object)("[" + kind + "] " + name + ": нет фото в папке " + library.Name + " — пропускаю"));
				}
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			SortedSet<string> sortedSet = new SortedSet<string>();
			SortedSet<string> sortedSet2 = new SortedSet<string>();
			foreach (Renderer renderer in renderers)
			{
				Material[] sharedMaterials = renderer.sharedMaterials;
				bool flag2 = false;
				for (int i = 0; i < sharedMaterials.Length; i++)
				{
					Material val = sharedMaterials[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					num++;
					string item = (((Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : "?");
					sortedSet.Add(item);
					if (OurMaterials.Contains(((Object)val).GetInstanceID()))
					{
						num3++;
						continue;
					}
					Material copy = GetCopy(val, photo);
					if ((Object)(object)copy == (Object)null)
					{
						sortedSet2.Add(item);
						continue;
					}
					sharedMaterials[i] = copy;
					flag2 = true;
					num2++;
				}
				if (flag2)
				{
					renderer.sharedMaterials = sharedMaterials;
				}
			}
			if (flag || num2 != 0)
			{
				string text = $"[{kind}] {name} → {photo.FileName} ({reason}) | заменено материалов: {num2 + num3} из {num}" + " | шейдеры: " + ((sortedSet.Count > 0) ? string.Join(", ", sortedSet) : "нет");
				if (sortedSet2.Count > 0)
				{
					text = text + " | без _BaseColorMap/_MainTex: " + string.Join(", ", sortedSet2);
				}
				Plugin.Log.LogInfo((object)text);
			}
		}

		private static Material GetCopy(Material src, Photo photo)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			string key = ((Object)src).GetInstanceID() + "|" + ((Object)photo.Texture).GetInstanceID();
			if (Copies.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if (!((IEnumerable<string>)TextureProps).Any((Func<string, bool>)src.HasProperty))
			{
				return null;
			}
			Material val = new Material(src)
			{
				name = ((Object)src).name + " (BirthdayPhoto)",
				hideFlags = (HideFlags)32
			};
			float num = Plugin.Tiling.Value;
			string[] textureProps = TextureProps;
			foreach (string text in textureProps)
			{
				if (val.HasProperty(text))
				{
					val.SetTexture(text, (Texture)(object)photo.Texture);
					val.SetTextureScale(text, new Vector2(num, num));
					val.SetTextureOffset(text, Vector2.zero);
				}
			}
			textureProps = ColorProps;
			foreach (string text2 in textureProps)
			{
				if (val.HasProperty(text2))
				{
					val.SetColor(text2, Color.white);
				}
			}
			Copies[key] = val;
			OurMaterials.Add(((Object)val).GetInstanceID());
			return val;
		}
	}
	internal static class PaintingSwapper
	{
		private static readonly Dictionary<string, string> Targets = new Dictionary<string, string>
		{
			{ "LethalGothicPainting", "classic_painting" },
			{ "RuinsByTheSea", "manor_painting_1" },
			{ "WallFallingDownPainting", "manor_painting_2" },
			{ "WallFallingDownPainting 1", "manor_painting_3" },
			{ "Posters", "ship_posters" }
		};

		private static readonly string[] TextureProps = new string[2] { "_BaseColorMap", "_MainTex" };

		private static readonly HashSet<int> Done = new HashSet<int>();

		public static void ApplyAll(string reason)
		{
			if (Plugin.Paintings == null || !Plugin.Paintings.Value || Plugin.PaintingPhotos.Count == 0)
			{
				return;
			}
			int num = 0;
			Material[] array = Resources.FindObjectsOfTypeAll<Material>();
			foreach (Material val in array)
			{
				if ((Object)(object)val == (Object)null || Done.Contains(((Object)val).GetInstanceID()))
				{
					continue;
				}
				string text = ((Object)val).name.Replace(" (Instance)", "");
				if (!Targets.TryGetValue(text, out var value))
				{
					continue;
				}
				Photo photo = Plugin.PaintingPhotos.Get(value);
				if (photo == null)
				{
					Plugin.Log.LogWarning((object)("[Картина] " + text + ": нет файла " + value + ".jpg в папке Paintings"));
					Done.Add(((Object)val).GetInstanceID());
					continue;
				}
				bool flag = false;
				string[] textureProps = TextureProps;
				foreach (string text2 in textureProps)
				{
					if (val.HasProperty(text2))
					{
						val.SetTexture(text2, (Texture)(object)photo.Texture);
						flag = true;
					}
				}
				Done.Add(((Object)val).GetInstanceID());
				if (flag)
				{
					num++;
					Plugin.Log.LogInfo((object)("[Картина] " + ((Object)val).name + " → " + photo.FileName + " | шейдер: " + (((Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : "?")));
				}
				else
				{
					Plugin.Log.LogWarning((object)("[Картина] " + ((Object)val).name + ": у шейдера " + (((Object)(object)val.shader != (Object)null) ? ((Object)val.shader).name : "?") + " нет _BaseColorMap/_MainTex"));
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)$"Картины заменены: {num} ({reason})");
			}
		}
	}
	internal static class Patches
	{
		private static readonly HashSet<string> StoreItemExclusions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "clipboard", "Sticky note", "Body" };

		public static void Apply(Harmony harmony)
		{
			Patch(harmony, typeof(EnemyAI), "Start", "EnemyStarted");
			Patch(harmony, typeof(MaskedPlayerEnemy), "Start", "EnemyStarted");
			Patch(harmony, typeof(MaskedPlayerEnemy), "SetSuit", "MaskedSuitChanged");
			Patch(harmony, typeof(GrabbableObject), "Start", "ItemStarted");
			Patch(harmony, typeof(CaveDwellerPhysicsProp), "Start", "ItemStarted");
			Patch(harmony, typeof(RoundManager), "SyncScrapValuesClientRpc", "ScrapValuesSynced");
			Patch(harmony, typeof(StartOfRound), "Start", "ShipLoaded");
			Patch(harmony, typeof(RoundManager), "FinishGeneratingLevel", "DungeonGenerated");
		}

		private static void Patch(Harmony harmony, Type type, string method, string postfix)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.DeclaredMethod(type, method, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Plugin.Log.LogWarning((object)("Метод " + type.Name + "." + method + " не найден — этот патч пропущен"));
				}
				else
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log.LogInfo((object)("Патч: " + type.Name + "." + method));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Не удалось пропатчить {type.Name}.{method}: {arg}");
			}
		}

		private static void EnemyStarted(EnemyAI __instance)
		{
			MaterialSwapper.Safe(delegate
			{
				if (Plugin.Enemies.Value)
				{
					MaterialSwapper.ApplyNextFrame((MonoBehaviour)(object)__instance, delegate
					{
						MaterialSwapper.ApplyEnemy(__instance);
					});
				}
			});
		}

		private static void MaskedSuitChanged(MaskedPlayerEnemy __instance)
		{
			MaterialSwapper.Safe(delegate
			{
				if (Plugin.Enemies.Value)
				{
					MaterialSwapper.ApplyEnemy((EnemyAI)(object)__instance);
				}
			});
		}

		private static void ItemStarted(GrabbableObject __instance)
		{
			MaterialSwapper.Safe(delegate
			{
				if (IsScrap(__instance))
				{
					MaterialSwapper.ApplyNextFrame((MonoBehaviour)(object)__instance, delegate
					{
						MaterialSwapper.ApplyItem(__instance);
					});
				}
				else if (IsStoreItem(__instance))
				{
					MaterialSwapper.ApplyNextFrame((MonoBehaviour)(object)__instance, delegate
					{
						MaterialSwapper.ApplyStoreItem(__instance);
					});
				}
			});
		}

		private static void DungeonGenerated()
		{
			MaterialSwapper.Safe(delegate
			{
				PaintingSwapper.ApplyAll("здание сгенерировано");
			});
		}

		private static void ScrapValuesSynced(NetworkObjectReference[] spawnedScrap)
		{
			MaterialSwapper.Safe(delegate
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				if (spawnedScrap != null)
				{
					NetworkObjectReference[] array = spawnedScrap;
					NetworkObject val2 = default(NetworkObject);
					for (int i = 0; i < array.Length; i++)
					{
						NetworkObjectReference val = array[i];
						if (((NetworkObjectReference)(ref val)).TryGet(ref val2, (NetworkManager)null))
						{
							GrabbableObject item = ((Component)val2).GetComponent<GrabbableObject>();
							if (IsScrap(item))
							{
								MaterialSwapper.Safe(delegate
								{
									MaterialSwapper.ApplyItem(item);
								});
							}
						}
					}
				}
			});
		}

		private static bool IsStoreItem(GrabbableObject item)
		{
			if (Plugin.StoreItems.Value && (Object)(object)item != (Object)null && (Object)(object)item.itemProperties != (Object)null && !item.itemProperties.isScrap && !(item is RagdollGrabbableObject) && !(item is CaveDwellerPhysicsProp))
			{
				return !StoreItemExclusions.Contains(item.itemProperties.itemName ?? "");
			}
			return false;
		}

		private static bool IsScrap(GrabbableObject item)
		{
			if (Plugin.Scrap.Value && (Object)(object)item != (Object)null && (Object)(object)item.itemProperties != (Object)null && item.itemProperties.isScrap)
			{
				return !(item is RagdollGrabbableObject);
			}
			return false;
		}

		private static void ShipLoaded(StartOfRound __instance)
		{
			MaterialSwapper.Safe(delegate
			{
				WriteNames(__instance);
			});
			MaterialSwapper.Safe(delegate
			{
				PaintingSwapper.ApplyAll("корабль загружен");
			});
		}

		private static void WriteNames(StartOfRound round)
		{
			SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
			EnemyType[] array = Resources.FindObjectsOfTypeAll<EnemyType>();
			foreach (EnemyType val in array)
			{
				Add(sortedSet, ((Object)(object)val != (Object)null) ? val.enemyName : null);
			}
			if (round.levels != null)
			{
				foreach (SelectableLevel item in round.levels.Where((SelectableLevel l) => (Object)(object)l != (Object)null))
				{
					List<SpawnableEnemyWithRarity>[] array2 = new List<SpawnableEnemyWithRarity>[3] { item.Enemies, item.OutsideEnemies, item.DaytimeEnemies };
					foreach (List<SpawnableEnemyWithRarity> list in array2)
					{
						if (list == null)
						{
							continue;
						}
						foreach (SpawnableEnemyWithRarity item2 in list)
						{
							Add(sortedSet, ((Object)(object)item2?.enemyType != (Object)null) ? item2.enemyType.enemyName : null);
						}
					}
				}
			}
			SortedSet<string> sortedSet2 = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
			SortedSet<string> sortedSet3 = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
			if ((Object)(object)round.allItemsList != (Object)null && round.allItemsList.itemsList != null)
			{
				foreach (Item items in round.allItemsList.itemsList)
				{
					if ((Object)(object)items != (Object)null)
					{
						Add(items.isScrap ? sortedSet2 : sortedSet3, items.itemName);
					}
				}
			}
			Directory.CreateDirectory(Plugin.PhotosDir);
			File.WriteAllLines(Path.Combine(Plugin.PhotosDir, "_enemy_names.txt"), sortedSet);
			File.WriteAllLines(Path.Combine(Plugin.PhotosDir, "_scrap_names.txt"), sortedSet2);
			if (Directory.Exists(Plugin.Photos2Dir))
			{
				File.WriteAllLines(Path.Combine(Plugin.Photos2Dir, "_item_names.txt"), sortedSet3);
			}
			Plugin.Log.LogInfo((object)($"Записаны имена: монстров {sortedSet.Count} (_enemy_names.txt), лута {sortedSet2.Count} (_scrap_names.txt), " + $"предметов магазина {sortedSet3.Count} (Photos2/_item_names.txt)"));
			Plugin.Log.LogInfo((object)("Монстры: " + string.Join(", ", sortedSet)));
		}

		private static void Add(SortedSet<string> set, string name)
		{
			if (!string.IsNullOrWhiteSpace(name))
			{
				set.Add(name.Trim());
			}
		}
	}
	internal class Photo
	{
		public string FileName;

		public string Key;

		public Texture2D Texture;
	}
	internal class PhotoLibrary
	{
		private static readonly string[] Extensions = new string[3] { ".jpg", ".jpeg", ".png" };

		private readonly List<Photo> _photos = new List<Photo>();

		private readonly Dictionary<string, KeyValuePair<Photo, string>> _choices = new Dictionary<string, KeyValuePair<Photo, string>>();

		public string Name { get; }

		public int Count => _photos.Count;

		public PhotoLibrary(string name)
		{
			Name = name;
		}

		public void Load(string dir, TextureWrapMode wrap = (TextureWrapMode)0)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			if (!Directory.Exists(dir))
			{
				Plugin.Log.LogWarning((object)("[" + Name + "] Папка не найдена: " + dir));
				return;
			}
			foreach (string item in (from f in Directory.GetFiles(dir)
				where Extensions.Contains(Path.GetExtension(f).ToLowerInvariant())
				select f).OrderBy<string, string>((string f) => Path.GetFileName(f), StringComparer.Ordinal))
			{
				try
				{
					Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
					if (!ImageConversion.LoadImage(val, File.ReadAllBytes(item), true))
					{
						Plugin.Log.LogError((object)("[" + Name + "] Не удалось прочитать картинку: " + item));
						continue;
					}
					((Object)val).name = "BirthdayPhoto_" + Path.GetFileName(item);
					((Texture)val).wrapMode = wrap;
					((Texture)val).filterMode = (FilterMode)2;
					((Texture)val).anisoLevel = 4;
					((Object)val).hideFlags = (HideFlags)32;
					_photos.Add(new Photo
					{
						FileName = Path.GetFileName(item),
						Key = Normalize(Path.GetFileNameWithoutExtension(item)),
						Texture = val
					});
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"[{Name}] Ошибка загрузки {item}: {arg}");
				}
			}
			Plugin.Log.LogInfo((object)$"[{Name}] Загружено фото: {_photos.Count} из {dir}");
		}

		public Photo Get(string fileNameWithoutExtension)
		{
			string key = Normalize(fileNameWithoutExtension);
			return _photos.FirstOrDefault((Photo p) => p.Key == key);
		}

		public Photo Choose(string name, out string reason, ulong salt = 0uL)
		{
			reason = null;
			if (_photos.Count == 0)
			{
				return null;
			}
			string text = Normalize(name ?? "");
			string key = text + "#" + salt;
			if (_choices.TryGetValue(key, out var value))
			{
				reason = value.Value;
				return value.Key;
			}
			Photo photo = null;
			if (text.Length > 0)
			{
				foreach (Photo photo2 in _photos)
				{
					if (photo2.Key.Contains(text) && (photo == null || photo2.Key.Length < photo.Key.Length))
					{
						photo = photo2;
					}
				}
			}
			if (photo != null)
			{
				reason = "по имени файла";
			}
			else
			{
				photo = _photos[(int)(Fnv1a((salt == 0L) ? text : (text + "#" + salt)) % (uint)_photos.Count)];
				reason = ((salt == 0L) ? "по хешу" : "по хешу экземпляра");
			}
			_choices[key] = new KeyValuePair<Photo, string>(photo, reason);
			return photo;
		}

		public static string Normalize(string s)
		{
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			string text = s.ToLowerInvariant();
			foreach (char c in text)
			{
				if (c != ' ' && c != '-' && c != '_')
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static uint Fnv1a(string s)
		{
			uint num = 2166136261u;
			byte[] bytes = Encoding.UTF8.GetBytes(s);
			foreach (byte b in bytes)
			{
				num ^= b;
				num *= 16777619;
			}
			return num;
		}
	}
	[BepInPlugin("birthday.birthdayphotos", "BirthdayPhotos", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "birthday.birthdayphotos";

		public const string PluginName = "BirthdayPhotos";

		public const string Version = "1.2.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enemies;

		internal static ConfigEntry<bool> Scrap;

		internal static ConfigEntry<bool> StoreItems;

		internal static ConfigEntry<bool> Paintings;

		internal static ConfigEntry<int> Tiling;

		internal static readonly PhotoLibrary MainPhotos = new PhotoLibrary("Photos");

		internal static readonly PhotoLibrary StorePhotos = new PhotoLibrary("Photos2");

		internal static readonly PhotoLibrary PaintingPhotos = new PhotoLibrary("Paintings");

		internal static string PhotosDir;

		internal static string Photos2Dir;

		private void Awake()
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Expected O, but got Unknown
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				Enemies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enemies", true, "Ставить фото на монстров (папка Photos)");
				Scrap = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Scrap", true, "Ставить фото на лут (scrap, папка Photos)");
				StoreItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StoreItems", true, "Ставить фото на предметы из магазина: фонарики, лопаты, рации и т.д. (папка Photos2)");
				Paintings = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Paintings", true, "Заменить картины в особняке, картину-украшение корабля и постеры на корабле (папка Paintings)");
				Tiling = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Tiling", 1, new ConfigDescription("1 = одно фото на материал, 3 = сетка 3×3 и т.д. (монстры и предметы)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
				PhotosDir = Path.Combine(directoryName, "Photos");
				Photos2Dir = Path.Combine(directoryName, "Photos2");
				MainPhotos.Load(PhotosDir, (TextureWrapMode)0);
				StorePhotos.Load(Photos2Dir, (TextureWrapMode)0);
				PaintingPhotos.Load(Path.Combine(directoryName, "Paintings"), (TextureWrapMode)1);
				Patches.Apply(new Harmony("birthday.birthdayphotos"));
				SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode _)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					MaterialSwapper.Safe(delegate
					{
						PaintingSwapper.ApplyAll("сцена " + ((Scene)(ref scene)).name);
					});
				};
				Log.LogInfo((object)(string.Format("{0} {1} загружен. Enemies={2}, Scrap={3}, ", "BirthdayPhotos", "1.2.0", Enemies.Value, Scrap.Value) + $"StoreItems={StoreItems.Value}, Paintings={Paintings.Value}, Tiling={Tiling.Value}"));
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Ошибка запуска плагина: {arg}");
			}
		}
	}
}