Decompiled source of PhotoScrap v1.1.0

BepInEx\plugins\Wang2-PhotoScrap\PhotoScrap.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LethalLib.Modules;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Wang2.PhotoScrap;

public sealed class PhotoFrameItem : PhysicsProp
{
	public GameObject Backing;

	public GameObject PhotoSurface;

	public GameObject TopBorder;

	public GameObject BottomBorder;

	public GameObject LeftBorder;

	public GameObject RightBorder;

	public BoxCollider FrameCollider;

	public ScanNodeProperties ScanNode;

	internal int LoadedPhotoToken;

	private ulong _lastPhotoId = ulong.MaxValue;

	private Texture2D _lastTexture;

	private Material _runtimePhotoMaterial;

	public override void Start()
	{
		((GrabbableObject)this).Start();
		RefreshPhoto();
	}

	public override void OnNetworkSpawn()
	{
		((NetworkBehaviour)this).OnNetworkSpawn();
		RefreshPhoto();
	}

	public override int GetItemDataToSave()
	{
		if (PhotoNetwork.TryGetFramePhotoId(((NetworkBehaviour)this).NetworkObjectId, out var photoId) && PhotoLibrary.TryGetToken(photoId, out var token))
		{
			return token;
		}
		return LoadedPhotoToken;
	}

	public override void LoadItemSaveData(int saveData)
	{
		((GrabbableObject)this).LoadItemSaveData(saveData);
		LoadedPhotoToken = saveData;
		if (((NetworkBehaviour)this).IsServer && ((NetworkBehaviour)this).IsSpawned)
		{
			PhotoAssignment.AssignSavedFrame(this);
		}
	}

	public override void OnNetworkDespawn()
	{
		PhotoNetwork.ForgetFrame(((NetworkBehaviour)this).NetworkObjectId);
		((NetworkBehaviour)this).OnNetworkDespawn();
	}

	internal void RefreshPhoto()
	{
		if (!PhotoNetwork.TryGetFramePhotoId(((NetworkBehaviour)this).NetworkObjectId, out var photoId))
		{
			photoId = 0uL;
		}
		Texture2D val = PhotoNetwork.GetTexture(photoId);
		if ((Object)(object)val == (Object)null)
		{
			val = PhotoScrapPlugin.PlaceholderTexture;
		}
		if (_lastPhotoId == photoId && (Object)(object)_lastTexture == (Object)(object)val)
		{
			UpdateScanValue();
			return;
		}
		_lastPhotoId = photoId;
		_lastTexture = val;
		ApplyPhoto(val, photoId);
		UpdateScanValue();
	}

	internal void UpdateScanValue()
	{
		if ((Object)(object)ScanNode != (Object)null)
		{
			ScanNode.scrapValue = ((GrabbableObject)this).scrapValue;
		}
	}

	private void ApplyPhoto(Texture2D texture, ulong photoId)
	{
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Expected O, but got Unknown
		if (!((Object)(object)texture == (Object)null) && !((Object)(object)PhotoSurface == (Object)null))
		{
			float num = Mathf.Clamp((float)((Texture)texture).width / (float)((Texture)texture).height, 0.45f, 2.15f);
			float num2;
			float num3;
			if (num >= 1f)
			{
				num2 = 0.72f;
				num3 = 0.72f / num;
			}
			else
			{
				num3 = 0.72f;
				num2 = 0.72f * num;
			}
			SetTransform(Backing.transform, new Vector3(0f, 0f, 0f), new Vector3(num2 + 0.12f, num3 + 0.12f, 0.04f));
			SetTransform(PhotoSurface.transform, new Vector3(0f, 0f, 0.031f), new Vector3(num2, num3, 0.012f));
			SetTransform(TopBorder.transform, new Vector3(0f, num3 * 0.5f + 0.03f, 0.045f), new Vector3(num2 + 0.12f, 0.06f, 0.075f));
			SetTransform(BottomBorder.transform, new Vector3(0f, (0f - num3) * 0.5f - 0.03f, 0.045f), new Vector3(num2 + 0.12f, 0.06f, 0.075f));
			SetTransform(LeftBorder.transform, new Vector3((0f - num2) * 0.5f - 0.03f, 0f, 0.045f), new Vector3(0.06f, num3, 0.075f));
			SetTransform(RightBorder.transform, new Vector3(num2 * 0.5f + 0.03f, 0f, 0.045f), new Vector3(0.06f, num3, 0.075f));
			if ((Object)(object)FrameCollider != (Object)null)
			{
				FrameCollider.center = new Vector3(0f, 0f, 0.025f);
				FrameCollider.size = new Vector3(num2 + 0.12f, num3 + 0.12f, 0.1f);
			}
			if ((Object)(object)_runtimePhotoMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_runtimePhotoMaterial);
			}
			_runtimePhotoMaterial = new Material(PhotoScrapPlugin.PhotoMaterialTemplate);
			((Object)_runtimePhotoMaterial).name = "PhotoScrap_RuntimePhoto_" + photoId.ToString("X16");
			PhotoScrapPlugin.SetMaterialTexture(_runtimePhotoMaterial, (Texture)(object)texture);
			((Renderer)PhotoSurface.GetComponent<MeshRenderer>()).sharedMaterial = _runtimePhotoMaterial;
		}
	}

	private static void SetTransform(Transform target, Vector3 position, Vector3 scale)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		target.localPosition = position;
		target.localRotation = Quaternion.identity;
		target.localScale = scale;
	}

	public override void OnDestroy()
	{
		if ((Object)(object)_runtimePhotoMaterial != (Object)null)
		{
			Object.Destroy((Object)(object)_runtimePhotoMaterial);
		}
		((GrabbableObject)this).OnDestroy();
	}
}
internal static class PhotoAssignment
{
	private static readonly List<PhotoRecord> Bag = new List<PhotoRecord>();

	private static readonly Random Random = new Random();

	private static ulong _lastPhotoId;

	internal static void ResetSession()
	{
		Bag.Clear();
		_lastPhotoId = 0uL;
	}

	internal static void StartNewRound()
	{
		Bag.Clear();
		_lastPhotoId = 0uL;
	}

	internal static void AssignSavedFrame(PhotoFrameItem frame)
	{
		if (!((Object)(object)frame == (Object)null) && ((NetworkBehaviour)frame).IsSpawned && !PhotoNetwork.TryGetFramePhotoId(((NetworkBehaviour)frame).NetworkObjectId, out var _))
		{
			if (frame.LoadedPhotoToken != 0 && PhotoLibrary.TryGetByToken(frame.LoadedPhotoToken, out var record))
			{
				PhotoNetwork.AssignFrame(((NetworkBehaviour)frame).NetworkObjectId, record.Id);
			}
			else
			{
				AssignNewFrame(frame);
			}
		}
	}

	internal static void AssignNewFrame(PhotoFrameItem frame)
	{
		if (!((Object)(object)frame == (Object)null) && ((NetworkBehaviour)frame).IsSpawned && !PhotoNetwork.TryGetFramePhotoId(((NetworkBehaviour)frame).NetworkObjectId, out var _))
		{
			ulong photoId2 = DrawPhoto()?.Id ?? 0;
			PhotoNetwork.AssignFrame(((NetworkBehaviour)frame).NetworkObjectId, photoId2);
		}
	}

	private static PhotoRecord DrawPhoto()
	{
		IList<PhotoRecord> records = PhotoLibrary.Records;
		if (records == null || records.Count == 0)
		{
			return null;
		}
		if (Bag.Count == 0)
		{
			for (int i = 0; i < records.Count; i++)
			{
				Bag.Add(records[i]);
			}
			for (int num = Bag.Count - 1; num > 0; num--)
			{
				int index = Random.Next(num + 1);
				PhotoRecord value = Bag[num];
				Bag[num] = Bag[index];
				Bag[index] = value;
			}
			if (Bag.Count > 1 && Bag[0].Id == _lastPhotoId)
			{
				PhotoRecord value2 = Bag[0];
				Bag[0] = Bag[1];
				Bag[1] = value2;
			}
		}
		PhotoRecord photoRecord = Bag[0];
		Bag.RemoveAt(0);
		_lastPhotoId = photoRecord.Id;
		return photoRecord;
	}
}
[HarmonyPatch(typeof(RoundManager), "SyncScrapValuesClientRpc")]
internal static class SyncScrapValuesPatch
{
	private sealed class FrameReference
	{
		public ulong NetworkId;

		public PhotoFrameItem Frame;
	}

	private static void Prefix(NetworkObjectReference[] spawnedScrap)
	{
		if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer || spawnedScrap == null)
		{
			return;
		}
		List<FrameReference> list = new List<FrameReference>();
		NetworkObject val = default(NetworkObject);
		for (int i = 0; i < spawnedScrap.Length; i++)
		{
			if (((NetworkObjectReference)(ref spawnedScrap[i])).TryGet(ref val, NetworkManager.Singleton) && !((Object)(object)val == (Object)null))
			{
				PhotoFrameItem component = ((Component)val).GetComponent<PhotoFrameItem>();
				if (!((Object)(object)component == (Object)null))
				{
					FrameReference frameReference = new FrameReference();
					frameReference.NetworkId = val.NetworkObjectId;
					frameReference.Frame = component;
					list.Add(frameReference);
				}
			}
		}
		list.Sort((FrameReference left, FrameReference right) => left.NetworkId.CompareTo(right.NetworkId));
		for (int num = 0; num < list.Count; num++)
		{
			PhotoAssignment.AssignNewFrame(list[num].Frame);
		}
	}
}
[HarmonyPatch(typeof(RoundManager), "LoadNewLevel")]
internal static class NewRoundPatch
{
	private static void Prefix()
	{
		if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
		{
			PhotoAssignment.StartNewRound();
		}
	}
}
[HarmonyPatch(typeof(GrabbableObject), "SetScrapValue")]
internal static class SetScrapValuePatch
{
	private static void Postfix(GrabbableObject __instance)
	{
		PhotoFrameItem photoFrameItem = __instance as PhotoFrameItem;
		if ((Object)(object)photoFrameItem != (Object)null)
		{
			photoFrameItem.UpdateScanValue();
		}
	}
}
internal sealed class PhotoRecord
{
	internal ulong Id;

	internal int Token;

	internal byte[] JpegBytes;

	internal int Width;

	internal int Height;

	internal string SourceName;
}
internal static class PhotoLibrary
{
	internal const int MaxNetworkPhotoBytes = 524288;

	private static readonly List<PhotoRecord> PhotoRecords = new List<PhotoRecord>();

	private static readonly Dictionary<ulong, PhotoRecord> ById = new Dictionary<ulong, PhotoRecord>();

	private static readonly Dictionary<int, PhotoRecord> ByToken = new Dictionary<int, PhotoRecord>();

	private static string _folder;

	private static int _maximumDimension;

	private static int _jpegQuality;

	private static int _maximumPhotos;

	private static long _maximumInputBytes;

	private static bool _loaded;

	internal static IList<PhotoRecord> Records => PhotoRecords.AsReadOnly();

	internal static void Configure(string folder, int maximumDimension, int jpegQuality, int maximumPhotos, int maximumInputMegabytes)
	{
		_folder = Environment.ExpandEnvironmentVariables(folder ?? string.Empty).Trim();
		_maximumDimension = maximumDimension;
		_jpegQuality = jpegQuality;
		_maximumPhotos = maximumPhotos;
		_maximumInputBytes = (long)maximumInputMegabytes * 1024L * 1024;
	}

	internal static void EnsureLoaded()
	{
		if (_loaded)
		{
			return;
		}
		_loaded = true;
		PhotoRecords.Clear();
		ById.Clear();
		ByToken.Clear();
		try
		{
			if (string.IsNullOrWhiteSpace(_folder))
			{
				string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
				_folder = Path.Combine(folderPath, "PhotoScrap");
			}
			_folder = Path.GetFullPath(_folder);
			Directory.CreateDirectory(_folder);
			string[] extensions = new string[3] { ".jpg", ".jpeg", ".png" };
			string[] array = (from path in Directory.GetFiles(_folder, "*", SearchOption.TopDirectoryOnly)
				where extensions.Contains(Path.GetExtension(path).ToLowerInvariant())
				select path).OrderBy<string, string>((string path) => Path.GetFileName(path), StringComparer.OrdinalIgnoreCase).Take(_maximumPhotos).ToArray();
			for (int num = 0; num < array.Length; num++)
			{
				TryLoadFile(array[num]);
			}
			if (PhotoRecords.Count == 0)
			{
				PhotoScrapPlugin.Log.LogWarning((object)("No usable host photos were found. Frames will use the placeholder. Folder: " + _folder));
				return;
			}
			PhotoScrapPlugin.Log.LogInfo((object)("Prepared " + PhotoRecords.Count + " host photos from: " + _folder));
		}
		catch (Exception ex)
		{
			PhotoScrapPlugin.Log.LogError((object)("Unable to load the host photo folder: " + ex));
		}
	}

	private static void TryLoadFile(string path)
	{
		try
		{
			FileInfo fileInfo = new FileInfo(path);
			if (!fileInfo.Exists || fileInfo.Length <= 0 || fileInfo.Length > _maximumInputBytes)
			{
				PhotoScrapPlugin.Log.LogWarning((object)("Skipped an empty or oversized photo: " + fileInfo.Name));
				return;
			}
			byte[] array = File.ReadAllBytes(path);
			byte[] rawHash = ComputeHash(array);
			string cachePath = GetCachePath(rawHash);
			byte[] array2 = null;
			int width = 0;
			int height = 0;
			if (File.Exists(cachePath))
			{
				byte[] array3 = File.ReadAllBytes(cachePath);
				if (array3.Length > 0 && array3.Length <= 524288 && TryReadJpegDimensions(array3, out width, out height))
				{
					array2 = array3;
				}
			}
			if (array2 == null)
			{
				array2 = CompressPhoto(array, out width, out height);
				if (array2 == null || array2.Length == 0 || array2.Length > 524288)
				{
					PhotoScrapPlugin.Log.LogWarning((object)("Skipped a photo that could not be compressed safely: " + fileInfo.Name));
					return;
				}
				try
				{
					Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
					File.WriteAllBytes(cachePath, array2);
				}
				catch (Exception ex)
				{
					PhotoScrapPlugin.Log.LogWarning((object)("Photo cache write failed: " + ex.Message));
				}
			}
			ulong num = ComputeId(array2);
			if (ById.ContainsKey(num))
			{
				return;
			}
			int num2 = (int)(num & 0x7FFFFFFF);
			if (num2 == 0)
			{
				num2 = 1;
			}
			while (ByToken.ContainsKey(num2))
			{
				num2 = (num2 * 397 + 17) & 0x7FFFFFFF;
				if (num2 == 0)
				{
					num2 = 1;
				}
			}
			PhotoRecord photoRecord = new PhotoRecord();
			photoRecord.Id = num;
			photoRecord.Token = num2;
			photoRecord.JpegBytes = array2;
			photoRecord.Width = width;
			photoRecord.Height = height;
			photoRecord.SourceName = fileInfo.Name;
			PhotoRecords.Add(photoRecord);
			ById.Add(num, photoRecord);
			ByToken.Add(num2, photoRecord);
		}
		catch (Exception ex2)
		{
			PhotoScrapPlugin.Log.LogWarning((object)("Skipped photo " + Path.GetFileName(path) + ": " + ex2.Message));
		}
	}

	private static string GetCachePath(byte[] rawHash)
	{
		string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "PhotoScrap", "Cache");
		string path2 = ToHex(rawHash) + "_" + _maximumDimension + "_" + _jpegQuality + ".jpg";
		return Path.Combine(path, path2);
	}

	private static byte[] CompressPhoto(byte[] sourceBytes, out int outputWidth, out int outputHeight)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		outputWidth = 0;
		outputHeight = 0;
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		((Object)val).name = "PhotoScrap_Source";
		if (!ImageConversion.LoadImage(val, sourceBytes, false))
		{
			Object.DestroyImmediate((Object)(object)val);
			return null;
		}
		int orientation = ReadExifOrientation(sourceBytes);
		int num = _maximumDimension;
		int num2 = _jpegQuality;
		byte[] array = null;
		try
		{
			for (int i = 0; i < 6; i++)
			{
				FitDimensions(((Texture)val).width, ((Texture)val).height, num, out var targetWidth, out var targetHeight);
				Texture2D val2 = Resize(val, targetWidth, targetHeight);
				Texture2D val3 = ApplyOrientation(val2, orientation);
				try
				{
					array = ImageConversion.EncodeToJPG(val3, num2);
					outputWidth = ((Texture)val3).width;
					outputHeight = ((Texture)val3).height;
				}
				finally
				{
					if ((Object)(object)val3 != (Object)(object)val2)
					{
						Object.DestroyImmediate((Object)(object)val3);
					}
					if ((Object)(object)val2 != (Object)(object)val)
					{
						Object.DestroyImmediate((Object)(object)val2);
					}
				}
				if (array == null || array.Length > 524288)
				{
					num = Math.Max(256, num * 3 / 4);
					num2 = Math.Max(55, num2 - 5);
					continue;
				}
				break;
			}
		}
		finally
		{
			Object.DestroyImmediate((Object)(object)val);
		}
		return array;
	}

	private static void FitDimensions(int width, int height, int maximum, out int targetWidth, out int targetHeight)
	{
		int num = Math.Max(width, height);
		if (num <= maximum)
		{
			targetWidth = width;
			targetHeight = height;
		}
		else
		{
			float num2 = (float)maximum / (float)num;
			targetWidth = Math.Max(1, Mathf.RoundToInt((float)width * num2));
			targetHeight = Math.Max(1, Mathf.RoundToInt((float)height * num2));
		}
	}

	private static Texture2D Resize(Texture2D source, int width, int height)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		if (((Texture)source).width == width && ((Texture)source).height == height)
		{
			return source;
		}
		RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
		RenderTexture active = RenderTexture.active;
		try
		{
			Graphics.Blit((Texture)(object)source, temporary);
			RenderTexture.active = temporary;
			Texture2D val = new Texture2D(width, height, (TextureFormat)3, false);
			((Object)val).name = "PhotoScrap_Resized";
			val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0, false);
			val.Apply(false, false);
			return val;
		}
		finally
		{
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
		}
	}

	private static Texture2D ApplyOrientation(Texture2D source, int orientation)
	{
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Expected O, but got Unknown
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		if (orientation <= 1 || orientation > 8)
		{
			return source;
		}
		int width = ((Texture)source).width;
		int height = ((Texture)source).height;
		bool flag = orientation >= 5;
		int num = (flag ? height : width);
		int num2 = (flag ? width : height);
		Color32[] pixels = source.GetPixels32();
		Color32[] array = (Color32[])(object)new Color32[num * num2];
		for (int i = 0; i < height; i++)
		{
			for (int j = 0; j < width; j++)
			{
				int num3 = j;
				int num4 = i;
				switch (orientation)
				{
				case 2:
					num3 = width - 1 - j;
					break;
				case 3:
					num3 = width - 1 - j;
					num4 = height - 1 - i;
					break;
				case 4:
					num4 = height - 1 - i;
					break;
				case 5:
					num3 = height - 1 - i;
					num4 = width - 1 - j;
					break;
				case 6:
					num3 = i;
					num4 = width - 1 - j;
					break;
				case 7:
					num3 = i;
					num4 = j;
					break;
				case 8:
					num3 = height - 1 - i;
					num4 = j;
					break;
				}
				ref Color32 reference = ref array[num4 * num + num3];
				reference = pixels[i * width + j];
			}
		}
		Texture2D val = new Texture2D(num, num2, (TextureFormat)3, false);
		((Object)val).name = "PhotoScrap_Oriented";
		val.SetPixels32(array);
		val.Apply(false, false);
		return val;
	}

	private static int ReadExifOrientation(byte[] bytes)
	{
		try
		{
			if (bytes == null || bytes.Length < 14 || bytes[0] != byte.MaxValue || bytes[1] != 216)
			{
				return 1;
			}
			int num;
			for (int i = 2; i + 4 < bytes.Length && bytes[i] == byte.MaxValue; i += 2 + num)
			{
				byte b = bytes[i + 1];
				num = (bytes[i + 2] << 8) | bytes[i + 3];
				if (num < 2 || i + 2 + num > bytes.Length)
				{
					break;
				}
				int num2 = i + 4;
				if (b != 225 || num < 16 || bytes[num2] != 69 || bytes[num2 + 1] != 120 || bytes[num2 + 2] != 105 || bytes[num2 + 3] != 102)
				{
					continue;
				}
				int num3 = num2 + 6;
				bool flag = bytes[num3] == 73 && bytes[num3 + 1] == 73;
				bool flag2 = bytes[num3] == 77 && bytes[num3 + 1] == 77;
				if (!flag && !flag2)
				{
					return 1;
				}
				uint num4 = ReadUInt32(bytes, num3 + 4, flag);
				int num5 = checked(num3 + (int)num4);
				ushort num6 = ReadUInt16(bytes, num5, flag);
				for (int j = 0; j < num6; j++)
				{
					int num7 = num5 + 2 + j * 12;
					if (num7 + 12 > bytes.Length)
					{
						break;
					}
					if (ReadUInt16(bytes, num7, flag) == 274)
					{
						int num8 = ReadUInt16(bytes, num7 + 8, flag);
						return (num8 < 1 || num8 > 8) ? 1 : num8;
					}
				}
			}
		}
		catch
		{
		}
		return 1;
	}

	private static ushort ReadUInt16(byte[] bytes, int offset, bool little)
	{
		if (offset < 0 || offset + 2 > bytes.Length)
		{
			throw new EndOfStreamException();
		}
		if (!little)
		{
			return (ushort)((bytes[offset] << 8) | bytes[offset + 1]);
		}
		return (ushort)(bytes[offset] | (bytes[offset + 1] << 8));
	}

	private static uint ReadUInt32(byte[] bytes, int offset, bool little)
	{
		if (offset < 0 || offset + 4 > bytes.Length)
		{
			throw new EndOfStreamException();
		}
		if (little)
		{
			return (uint)(bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24));
		}
		return (uint)((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]);
	}

	internal static ulong ComputeId(byte[] bytes)
	{
		byte[] value = ComputeHash(bytes);
		ulong num = BitConverter.ToUInt64(value, 0);
		if (num != 0)
		{
			return num;
		}
		return 6287392622479692611uL;
	}

	private static byte[] ComputeHash(byte[] bytes)
	{
		using SHA256 sHA = SHA256.Create();
		return sHA.ComputeHash(bytes);
	}

	private static string ToHex(byte[] bytes)
	{
		StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2);
		for (int i = 0; i < bytes.Length; i++)
		{
			stringBuilder.Append(bytes[i].ToString("x2"));
		}
		return stringBuilder.ToString();
	}

	internal static bool TryGetRecord(ulong id, out PhotoRecord record)
	{
		return ById.TryGetValue(id, out record);
	}

	internal static bool TryGetByToken(int token, out PhotoRecord record)
	{
		return ByToken.TryGetValue(token, out record);
	}

	internal static bool TryGetToken(ulong id, out int token)
	{
		if (ById.TryGetValue(id, out var value))
		{
			token = value.Token;
			return true;
		}
		token = 0;
		return false;
	}

	internal static bool TryReadJpegDimensions(byte[] bytes, out int width, out int height)
	{
		width = 0;
		height = 0;
		try
		{
			if (bytes == null || bytes.Length < 4 || bytes[0] != byte.MaxValue || bytes[1] != 216)
			{
				return false;
			}
			int num;
			for (int i = 2; i + 8 < bytes.Length; i += 2 + num)
			{
				if (bytes[i] != byte.MaxValue)
				{
					return false;
				}
				byte b = bytes[i + 1];
				num = (bytes[i + 2] << 8) | bytes[i + 3];
				if (num < 2 || i + 2 + num > bytes.Length)
				{
					return false;
				}
				if (b >= 192 && b <= 207 && b != 196 && b != 200 && b != 204)
				{
					height = (bytes[i + 5] << 8) | bytes[i + 6];
					width = (bytes[i + 7] << 8) | bytes[i + 8];
					return width > 0 && height > 0 && width <= 4096 && height <= 4096;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	internal static void Shutdown()
	{
		PhotoRecords.Clear();
		ById.Clear();
		ByToken.Clear();
		_loaded = false;
	}
}
internal static class PhotoNetwork
{
	private sealed class ReceiveState
	{
		internal byte[] Buffer;

		internal int NextOffset;
	}

	private const int ProtocolVersion = 2;

	private const int ChunkSize = 12288;

	private const string HelloMessage = "W2PS_110_HELLO";

	private const string AcknowledgeMessage = "W2PS_110_ACK";

	private const string BeginMessage = "W2PS_110_BEGIN";

	private const string ChunkMessage = "W2PS_110_CHUNK";

	private const string AssignmentMessage = "W2PS_110_ASSIGN";

	private static readonly Dictionary<ulong, ulong> FramePhotos = new Dictionary<ulong, ulong>();

	private static readonly Dictionary<ulong, byte[]> RemotePhotos = new Dictionary<ulong, byte[]>();

	private static readonly Dictionary<ulong, Texture2D> Textures = new Dictionary<ulong, Texture2D>();

	private static readonly Dictionary<ulong, ReceiveState> Receiving = new Dictionary<ulong, ReceiveState>();

	private static readonly HashSet<ulong> ReadyClients = new HashSet<ulong>();

	private static readonly Dictionary<ulong, HashSet<ulong>> SentPhotos = new Dictionary<ulong, HashSet<ulong>>();

	private static NetworkManager _manager;

	private static bool _serverAcknowledged;

	private static float _nextHelloTime;

	internal static void Tick()
	{
		NetworkManager singleton = NetworkManager.Singleton;
		if ((Object)(object)singleton == (Object)null || !singleton.IsListening)
		{
			if ((Object)(object)_manager != (Object)null)
			{
				Detach();
			}
			return;
		}
		if ((Object)(object)_manager != (Object)(object)singleton)
		{
			Attach(singleton);
		}
		if ((Object)(object)_manager != (Object)null && _manager.IsClient && !_manager.IsServer && _manager.IsConnectedClient && !_serverAcknowledged && Time.realtimeSinceStartup >= _nextHelloTime)
		{
			SendHello();
			_nextHelloTime = Time.realtimeSinceStartup + 3f;
		}
	}

	private static void Attach(NetworkManager manager)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Expected O, but got Unknown
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Expected O, but got Unknown
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Expected O, but got Unknown
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Expected O, but got Unknown
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Expected O, but got Unknown
		Detach();
		_manager = manager;
		ClearSessionState();
		CustomMessagingManager customMessagingManager = manager.CustomMessagingManager;
		customMessagingManager.RegisterNamedMessageHandler("W2PS_110_HELLO", new HandleNamedMessageDelegate(HandleHello));
		customMessagingManager.RegisterNamedMessageHandler("W2PS_110_ACK", new HandleNamedMessageDelegate(HandleAcknowledge));
		customMessagingManager.RegisterNamedMessageHandler("W2PS_110_BEGIN", new HandleNamedMessageDelegate(HandleBegin));
		customMessagingManager.RegisterNamedMessageHandler("W2PS_110_CHUNK", new HandleNamedMessageDelegate(HandleChunk));
		customMessagingManager.RegisterNamedMessageHandler("W2PS_110_ASSIGN", new HandleNamedMessageDelegate(HandleAssignment));
		manager.OnClientConnectedCallback += HandleClientConnected;
		manager.OnClientDisconnectCallback += HandleClientDisconnected;
		if (manager.IsServer)
		{
			PhotoLibrary.EnsureLoaded();
		}
		if (manager.IsClient && !manager.IsServer && manager.IsConnectedClient)
		{
			SendHello();
		}
	}

	private static void Detach()
	{
		if ((Object)(object)_manager != (Object)null)
		{
			try
			{
				CustomMessagingManager customMessagingManager = _manager.CustomMessagingManager;
				if (customMessagingManager != null)
				{
					customMessagingManager.UnregisterNamedMessageHandler("W2PS_110_HELLO");
					customMessagingManager.UnregisterNamedMessageHandler("W2PS_110_ACK");
					customMessagingManager.UnregisterNamedMessageHandler("W2PS_110_BEGIN");
					customMessagingManager.UnregisterNamedMessageHandler("W2PS_110_CHUNK");
					customMessagingManager.UnregisterNamedMessageHandler("W2PS_110_ASSIGN");
				}
				_manager.OnClientConnectedCallback -= HandleClientConnected;
				_manager.OnClientDisconnectCallback -= HandleClientDisconnected;
			}
			catch
			{
			}
		}
		_manager = null;
		ClearSessionState();
	}

	private static void ClearSessionState()
	{
		FramePhotos.Clear();
		RemotePhotos.Clear();
		Receiving.Clear();
		ReadyClients.Clear();
		SentPhotos.Clear();
		foreach (Texture2D value in Textures.Values)
		{
			if ((Object)(object)value != (Object)null)
			{
				Object.Destroy((Object)(object)value);
			}
		}
		Textures.Clear();
		PhotoAssignment.ResetSession();
		_serverAcknowledged = false;
		_nextHelloTime = 0f;
	}

	internal static void Shutdown()
	{
		Detach();
	}

	private static void HandleClientConnected(ulong clientId)
	{
		if (!((Object)(object)_manager == (Object)null))
		{
			if (_manager.IsServer && clientId != _manager.LocalClientId)
			{
				SentPhotos[clientId] = new HashSet<ulong>();
			}
			if (_manager.IsClient && !_manager.IsServer && clientId == _manager.LocalClientId)
			{
				SendHello();
			}
		}
	}

	private static void HandleClientDisconnected(ulong clientId)
	{
		ReadyClients.Remove(clientId);
		SentPhotos.Remove(clientId);
		if ((Object)(object)_manager != (Object)null && clientId == _manager.LocalClientId)
		{
			_serverAcknowledged = false;
		}
	}

	private static void SendHello()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_manager == (Object)null || !_manager.IsClient || _manager.IsServer || !_manager.IsConnectedClient)
		{
			return;
		}
		FastBufferWriter writer = new FastBufferWriter(4, (Allocator)2, 4);
		try
		{
			WriteInt32(ref writer, 2);
			_manager.CustomMessagingManager.SendNamedMessage("W2PS_110_HELLO", 0uL, writer, (NetworkDelivery)3);
		}
		finally
		{
			((FastBufferWriter)(ref writer)).Dispose();
		}
	}

	private static void HandleHello(ulong senderClientId, FastBufferReader reader)
	{
		if ((Object)(object)_manager == (Object)null || !_manager.IsServer || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position < 4)
		{
			return;
		}
		int num = ReadInt32(ref reader);
		if (num != 2)
		{
			PhotoScrapPlugin.Log.LogWarning((object)("Client " + senderClientId + " uses an incompatible PhotoScrap protocol."));
			return;
		}
		ReadyClients.Add(senderClientId);
		if (!SentPhotos.ContainsKey(senderClientId))
		{
			SentPhotos[senderClientId] = new HashSet<ulong>();
		}
		SendAcknowledge(senderClientId);
		SendAllState(senderClientId);
	}

	private static void SendAcknowledge(ulong clientId)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		FastBufferWriter writer = new FastBufferWriter(4, (Allocator)2, 4);
		try
		{
			WriteInt32(ref writer, 2);
			_manager.CustomMessagingManager.SendNamedMessage("W2PS_110_ACK", clientId, writer, (NetworkDelivery)3);
		}
		finally
		{
			((FastBufferWriter)(ref writer)).Dispose();
		}
	}

	private static void HandleAcknowledge(ulong senderClientId, FastBufferReader reader)
	{
		if (!((Object)(object)_manager == (Object)null) && _manager.IsClient && !_manager.IsServer && senderClientId == 0 && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 4)
		{
			int num = ReadInt32(ref reader);
			if (num == 2)
			{
				_serverAcknowledged = true;
			}
		}
	}

	internal static void AssignFrame(ulong networkObjectId, ulong photoId)
	{
		FramePhotos[networkObjectId] = photoId;
		RefreshFrame(networkObjectId);
		if (!((Object)(object)_manager == (Object)null) && _manager.IsServer)
		{
			ulong[] array = ReadyClients.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				SendStateForFrame(array[i], networkObjectId, photoId);
			}
		}
	}

	private static void SendAllState(ulong clientId)
	{
		KeyValuePair<ulong, ulong>[] array = FramePhotos.ToArray();
		for (int i = 0; i < array.Length; i++)
		{
			SendStateForFrame(clientId, array[i].Key, array[i].Value);
		}
	}

	private static void SendStateForFrame(ulong clientId, ulong networkObjectId, ulong photoId)
	{
		if (ReadyClients.Contains(clientId) && !((Object)(object)_manager == (Object)null) && _manager.IsServer)
		{
			if (photoId != 0)
			{
				SendPhotoIfNeeded(clientId, photoId);
			}
			SendAssignment(clientId, networkObjectId, photoId);
		}
	}

	private static void SendPhotoIfNeeded(ulong clientId, ulong photoId)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		if (!SentPhotos.TryGetValue(clientId, out var value))
		{
			value = new HashSet<ulong>();
			SentPhotos[clientId] = value;
		}
		if (value.Contains(photoId) || !PhotoLibrary.TryGetRecord(photoId, out var record) || record.JpegBytes == null)
		{
			return;
		}
		byte[] jpegBytes = record.JpegBytes;
		if (jpegBytes.Length <= 0 || jpegBytes.Length > 524288)
		{
			return;
		}
		FastBufferWriter writer = new FastBufferWriter(12, (Allocator)2, 12);
		try
		{
			WriteUInt64(ref writer, photoId);
			WriteInt32(ref writer, jpegBytes.Length);
			_manager.CustomMessagingManager.SendNamedMessage("W2PS_110_BEGIN", clientId, writer, (NetworkDelivery)4);
		}
		finally
		{
			((FastBufferWriter)(ref writer)).Dispose();
		}
		int num;
		for (int i = 0; i < jpegBytes.Length; i += num)
		{
			num = Math.Min(12288, jpegBytes.Length - i);
			int num2 = 16 + num;
			FastBufferWriter writer2 = new FastBufferWriter(num2, (Allocator)2, num2);
			try
			{
				WriteUInt64(ref writer2, photoId);
				WriteInt32(ref writer2, i);
				WriteInt32(ref writer2, num);
				for (int j = 0; j < num; j++)
				{
					((FastBufferWriter)(ref writer2)).WriteByteSafe(jpegBytes[i + j]);
				}
				_manager.CustomMessagingManager.SendNamedMessage("W2PS_110_CHUNK", clientId, writer2, (NetworkDelivery)4);
			}
			finally
			{
				((FastBufferWriter)(ref writer2)).Dispose();
			}
		}
		value.Add(photoId);
	}

	private static void SendAssignment(ulong clientId, ulong networkObjectId, ulong photoId)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		FastBufferWriter writer = new FastBufferWriter(16, (Allocator)2, 16);
		try
		{
			WriteUInt64(ref writer, networkObjectId);
			WriteUInt64(ref writer, photoId);
			_manager.CustomMessagingManager.SendNamedMessage("W2PS_110_ASSIGN", clientId, writer, (NetworkDelivery)4);
		}
		finally
		{
			((FastBufferWriter)(ref writer)).Dispose();
		}
	}

	private static void HandleBegin(ulong senderClientId, FastBufferReader reader)
	{
		if (IsValidServerMessage(senderClientId) && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 12)
		{
			ulong num = ReadUInt64(ref reader);
			int num2 = ReadInt32(ref reader);
			if (num != 0 && num2 > 0 && num2 <= 524288)
			{
				ReceiveState receiveState = new ReceiveState();
				receiveState.Buffer = new byte[num2];
				receiveState.NextOffset = 0;
				Receiving[num] = receiveState;
			}
		}
	}

	private static void HandleChunk(ulong senderClientId, FastBufferReader reader)
	{
		if (!IsValidServerMessage(senderClientId) || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position < 16)
		{
			return;
		}
		ulong num = ReadUInt64(ref reader);
		int num2 = ReadInt32(ref reader);
		int num3 = ReadInt32(ref reader);
		if (!Receiving.TryGetValue(num, out var value) || num3 <= 0 || num3 > 12288 || num2 != value.NextOffset || num2 < 0 || num2 + num3 > value.Buffer.Length || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position < num3)
		{
			Receiving.Remove(num);
			return;
		}
		byte[] array = new byte[num3];
		for (int i = 0; i < num3; i++)
		{
			((FastBufferReader)(ref reader)).ReadByteSafe(ref array[i]);
		}
		Buffer.BlockCopy(array, 0, value.Buffer, num2, num3);
		value.NextOffset += num3;
		if (value.NextOffset == value.Buffer.Length)
		{
			Receiving.Remove(num);
			if (PhotoLibrary.ComputeId(value.Buffer) != num)
			{
				PhotoScrapPlugin.Log.LogWarning((object)"Rejected a photo with an invalid network hash.");
				return;
			}
			if (!PhotoLibrary.TryReadJpegDimensions(value.Buffer, out var _, out var _))
			{
				PhotoScrapPlugin.Log.LogWarning((object)"Rejected invalid JPEG data from the host.");
				return;
			}
			RemotePhotos[num] = value.Buffer;
			RefreshFramesUsingPhoto(num);
		}
	}

	private static void HandleAssignment(ulong senderClientId, FastBufferReader reader)
	{
		if (IsValidServerMessage(senderClientId) && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 16)
		{
			ulong num = ReadUInt64(ref reader);
			ulong value = ReadUInt64(ref reader);
			FramePhotos[num] = value;
			RefreshFrame(num);
		}
	}

	private static bool IsValidServerMessage(ulong senderClientId)
	{
		if ((Object)(object)_manager != (Object)null && _manager.IsClient && !_manager.IsServer)
		{
			return senderClientId == 0;
		}
		return false;
	}

	internal static bool TryGetFramePhotoId(ulong networkObjectId, out ulong photoId)
	{
		return FramePhotos.TryGetValue(networkObjectId, out photoId);
	}

	internal static Texture2D GetTexture(ulong photoId)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Expected O, but got Unknown
		if (photoId == 0)
		{
			return PhotoScrapPlugin.PlaceholderTexture;
		}
		if (Textures.TryGetValue(photoId, out var value) && (Object)(object)value != (Object)null)
		{
			return value;
		}
		byte[] value2 = null;
		if (PhotoLibrary.TryGetRecord(photoId, out var record))
		{
			value2 = record.JpegBytes;
		}
		else
		{
			RemotePhotos.TryGetValue(photoId, out value2);
		}
		if (value2 == null)
		{
			return PhotoScrapPlugin.PlaceholderTexture;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)3, false);
		((Object)val).name = "PhotoScrap_NetworkPhoto_" + photoId.ToString("X16");
		if (!ImageConversion.LoadImage(val, value2, true))
		{
			Object.Destroy((Object)(object)val);
			return PhotoScrapPlugin.PlaceholderTexture;
		}
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)1;
		Textures[photoId] = val;
		return val;
	}

	private static void RefreshFrame(ulong networkObjectId)
	{
		PhotoFrameItem[] array = Object.FindObjectsOfType<PhotoFrameItem>();
		for (int i = 0; i < array.Length; i++)
		{
			if (((NetworkBehaviour)array[i]).IsSpawned && ((NetworkBehaviour)array[i]).NetworkObjectId == networkObjectId)
			{
				array[i].RefreshPhoto();
			}
		}
	}

	private static void RefreshFramesUsingPhoto(ulong photoId)
	{
		ulong[] array = (from pair in FramePhotos
			where pair.Value == photoId
			select pair.Key).ToArray();
		for (int num = 0; num < array.Length; num++)
		{
			RefreshFrame(array[num]);
		}
	}

	internal static void ForgetFrame(ulong networkObjectId)
	{
		FramePhotos.Remove(networkObjectId);
	}

	private static void WriteInt32(ref FastBufferWriter writer, int value)
	{
		((FastBufferWriter)(ref writer)).WriteByteSafe((byte)value);
		((FastBufferWriter)(ref writer)).WriteByteSafe((byte)(value >> 8));
		((FastBufferWriter)(ref writer)).WriteByteSafe((byte)(value >> 16));
		((FastBufferWriter)(ref writer)).WriteByteSafe((byte)(value >> 24));
	}

	private static int ReadInt32(ref FastBufferReader reader)
	{
		byte b = default(byte);
		((FastBufferReader)(ref reader)).ReadByteSafe(ref b);
		byte b2 = default(byte);
		((FastBufferReader)(ref reader)).ReadByteSafe(ref b2);
		byte b3 = default(byte);
		((FastBufferReader)(ref reader)).ReadByteSafe(ref b3);
		byte b4 = default(byte);
		((FastBufferReader)(ref reader)).ReadByteSafe(ref b4);
		return b | (b2 << 8) | (b3 << 16) | (b4 << 24);
	}

	private static void WriteUInt64(ref FastBufferWriter writer, ulong value)
	{
		for (int i = 0; i < 64; i += 8)
		{
			((FastBufferWriter)(ref writer)).WriteByteSafe((byte)(value >> i));
		}
	}

	private static ulong ReadUInt64(ref FastBufferReader reader)
	{
		ulong num = 0uL;
		byte b = default(byte);
		for (int i = 0; i < 64; i += 8)
		{
			((FastBufferReader)(ref reader)).ReadByteSafe(ref b);
			num |= (ulong)b << i;
		}
		return num;
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("wang2.photoscrap", "PhotoScrap", "1.1.0")]
public sealed class PhotoScrapPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "wang2.photoscrap";

	public const string PluginName = "PhotoScrap";

	public const string PluginVersion = "1.1.0";

	public const int MinimumValue = 80;

	public const int MaximumValue = 140;

	internal static PhotoScrapPlugin Instance;

	internal static ManualLogSource Log;

	internal static Material PhotoMaterialTemplate;

	internal static Material FrameMaterial;

	internal static Material BackMaterial;

	internal static Texture2D PlaceholderTexture;

	private ConfigEntry<int> _spawnWeight;

	private void Awake()
	{
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "PhotoScrap");
		_spawnWeight = ((BaseUnityPlugin)this).Config.Bind<int>("Spawn", "Rarity", 65, "Relative spawn weight on all moons. 65 aims for a fairly common one or two frames per round.");
		ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("Photos", "Folder", text, "Folder read only when this player is the host. Restart the game after changing photos.");
		ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Photos", "MaximumDimension", 1024, "Maximum width or height after compression (256-2048).");
		ConfigEntry<int> val3 = ((BaseUnityPlugin)this).Config.Bind<int>("Photos", "JpegQuality", 82, "JPEG compression quality (55-95).");
		ConfigEntry<int> val4 = ((BaseUnityPlugin)this).Config.Bind<int>("Photos", "MaximumPhotos", 64, "Maximum number of files read from the host photo folder (1-128).");
		ConfigEntry<int> val5 = ((BaseUnityPlugin)this).Config.Bind<int>("Photos", "MaximumInputMegabytes", 20, "Maximum size of one source image in MiB (1-100).");
		PhotoLibrary.Configure(val.Value, Mathf.Clamp(val2.Value, 256, 2048), Mathf.Clamp(val3.Value, 55, 95), Mathf.Clamp(val4.Value, 1, 128), Mathf.Clamp(val5.Value, 1, 100));
		try
		{
			CreateMaterials();
			RegisterPhotoScrap();
			new Harmony("wang2.photoscrap").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("PhotoScrap 1.1.0 loaded. Host photos will be read from: " + val.Value));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("PhotoScrap failed to initialize: " + ex));
		}
	}

	private void Update()
	{
		PhotoNetwork.Tick();
	}

	private void OnDestroy()
	{
		PhotoNetwork.Shutdown();
		PhotoLibrary.Shutdown();
	}

	private static Shader FindShader(params string[] names)
	{
		for (int i = 0; i < names.Length; i++)
		{
			Shader val = Shader.Find(names[i]);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
		}
		throw new InvalidOperationException("No compatible material shader was found.");
	}

	private void CreateMaterials()
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Expected O, but got Unknown
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Expected O, but got Unknown
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Expected O, but got Unknown
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		Shader val = FindShader("HDRP/Lit", "Standard");
		Shader val2 = FindShader("HDRP/Unlit", "Unlit/Texture", "Standard");
		FrameMaterial = new Material(val);
		((Object)FrameMaterial).name = "PhotoScrap_AgedIron";
		SetMaterialColor(FrameMaterial, new Color(0.16f, 0.105f, 0.075f, 1f));
		SetMaterialFloat(FrameMaterial, "_Metallic", 0.62f);
		SetMaterialFloat(FrameMaterial, "_Smoothness", 0.22f);
		BackMaterial = new Material(val);
		((Object)BackMaterial).name = "PhotoScrap_OldBacking";
		SetMaterialColor(BackMaterial, new Color(0.055f, 0.045f, 0.04f, 1f));
		SetMaterialFloat(BackMaterial, "_Metallic", 0.12f);
		SetMaterialFloat(BackMaterial, "_Smoothness", 0.08f);
		PlaceholderTexture = CreatePlaceholderTexture();
		PhotoMaterialTemplate = new Material(val2);
		((Object)PhotoMaterialTemplate).name = "PhotoScrap_PhotoTemplate";
		SetMaterialColor(PhotoMaterialTemplate, Color.white);
		SetMaterialTexture(PhotoMaterialTemplate, (Texture)(object)PlaceholderTexture);
	}

	private static Texture2D CreatePlaceholderTexture()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(64, 64, (TextureFormat)3, false);
		((Object)val).name = "PhotoScrap_Placeholder";
		Color32[] array = (Color32[])(object)new Color32[4096];
		for (int i = 0; i < 64; i++)
		{
			for (int j = 0; j < 64; j++)
			{
				bool flag = j < 5 || i < 5 || j >= 59 || i >= 59;
				bool flag2 = Math.Abs(j - i) < 3 || Math.Abs(63 - j - i) < 3;
				ref Color32 reference = ref array[i * 64 + j];
				reference = (flag ? new Color32((byte)82, (byte)55, (byte)40, byte.MaxValue) : (flag2 ? new Color32((byte)102, (byte)92, (byte)76, byte.MaxValue) : new Color32((byte)42, (byte)39, (byte)35, byte.MaxValue)));
			}
		}
		val.SetPixels32(array);
		val.Apply(false, true);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)1;
		return val;
	}

	private static void SetMaterialColor(Material material, Color color)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		if (material.HasProperty("_Color"))
		{
			material.SetColor("_Color", color);
		}
		if (material.HasProperty("_BaseColor"))
		{
			material.SetColor("_BaseColor", color);
		}
		if (material.HasProperty("_UnlitColor"))
		{
			material.SetColor("_UnlitColor", color);
		}
	}

	private static void SetMaterialFloat(Material material, string property, float value)
	{
		if (material.HasProperty(property))
		{
			material.SetFloat(property, value);
		}
	}

	internal static void SetMaterialTexture(Material material, Texture texture)
	{
		material.mainTexture = texture;
		if (material.HasProperty("_BaseColorMap"))
		{
			material.SetTexture("_BaseColorMap", texture);
		}
		if (material.HasProperty("_UnlitColorMap"))
		{
			material.SetTexture("_UnlitColorMap", texture);
		}
	}

	private void RegisterPhotoScrap()
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_020b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Expected O, but got Unknown
		Item val = ScriptableObject.CreateInstance<Item>();
		((Object)val).name = "PhotoScrapItem";
		val.itemName = "旧日合影";
		val.itemId = 9251201;
		val.isScrap = true;
		val.minValue = 80;
		val.maxValue = 140;
		val.weight = 1.08f;
		val.twoHanded = false;
		val.twoHandedAnimation = false;
		val.canBeGrabbedBeforeGameStart = true;
		val.itemSpawnsOnGround = true;
		val.isConductiveMetal = true;
		val.requiresBattery = false;
		val.grabAnimationTime = 0.4f;
		val.saveItemVariable = true;
		val.allowDroppingAheadOfPlayer = true;
		val.positionOffset = new Vector3(0.08f, 0.02f, 0.18f);
		val.rotationOffset = new Vector3(0f, 90f, 95f);
		val.restingRotation = new Vector3(0f, 0f, 90f);
		val.verticalOffset = 0.06f;
		val.toolTips = new string[0];
		Item val2 = ((IEnumerable<Item>)Resources.FindObjectsOfTypeAll<Item>()).FirstOrDefault((Func<Item, bool>)((Item candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.grabSFX != (Object)null && (Object)(object)candidate.dropSFX != (Object)null));
		if ((Object)(object)val2 != (Object)null)
		{
			val.grabSFX = val2.grabSFX;
			val.dropSFX = val2.dropSFX;
			val.pocketSFX = val2.pocketSFX;
			val.throwSFX = val2.throwSFX;
			val.clinkAudios = val2.clinkAudios;
		}
		GameObject val3 = NetworkPrefabs.CreateNetworkPrefab("Wang2_PhotoScrap_Prefab");
		val3.layer = 6;
		Rigidbody val4 = val3.AddComponent<Rigidbody>();
		val4.mass = 1.15f;
		val4.drag = 0.08f;
		val4.angularDrag = 0.08f;
		BoxCollider val5 = val3.AddComponent<BoxCollider>();
		val5.size = new Vector3(0.84f, 0.58f, 0.09f);
		PhotoFrameItem photoFrameItem = val3.AddComponent<PhotoFrameItem>();
		((GrabbableObject)photoFrameItem).itemProperties = val;
		((GrabbableObject)photoFrameItem).grabbable = true;
		((GrabbableObject)photoFrameItem).grabbableToEnemies = true;
		((GrabbableObject)photoFrameItem).propBody = val4;
		((GrabbableObject)photoFrameItem).propColliders = (Collider[])(object)new Collider[1] { (Collider)val5 };
		photoFrameItem.FrameCollider = val5;
		Transform transform = new GameObject("PhotoFrameVisuals").transform;
		transform.SetParent(val3.transform, false);
		photoFrameItem.Backing = CreateBox("Backing", transform, BackMaterial);
		photoFrameItem.PhotoSurface = CreateBox("Photo", transform, PhotoMaterialTemplate);
		photoFrameItem.TopBorder = CreateBox("TopBorder", transform, FrameMaterial);
		photoFrameItem.BottomBorder = CreateBox("BottomBorder", transform, FrameMaterial);
		photoFrameItem.LeftBorder = CreateBox("LeftBorder", transform, FrameMaterial);
		photoFrameItem.RightBorder = CreateBox("RightBorder", transform, FrameMaterial);
		((GrabbableObject)photoFrameItem).mainObjectRenderer = photoFrameItem.Backing.GetComponent<MeshRenderer>();
		GameObject val6 = new GameObject("ScanNode");
		val6.layer = 22;
		val6.transform.SetParent(val3.transform, false);
		ScanNodeProperties val7 = val6.AddComponent<ScanNodeProperties>();
		val7.headerText = "旧日合影";
		val7.subText = "价值:";
		val7.nodeType = 2;
		val7.minRange = 1;
		val7.maxRange = 13;
		val7.requiresLineOfSight = true;
		photoFrameItem.ScanNode = val7;
		val.spawnPrefab = val3;
		NetworkPrefabs.RegisterNetworkPrefab(val3);
		Items.RegisterScrap(val, Mathf.Clamp(_spawnWeight.Value, 0, 999), (LevelTypes)(-1));
	}

	private static GameObject CreateBox(string name, Transform parent, Material material)
	{
		GameObject val = GameObject.CreatePrimitive((PrimitiveType)3);
		((Object)val).name = name;
		val.layer = 6;
		val.transform.SetParent(parent, false);
		Collider component = val.GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			Object.Destroy((Object)(object)component);
		}
		((Renderer)val.GetComponent<MeshRenderer>()).sharedMaterial = material;
		return val;
	}
}