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()).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 Bag = new List(); 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 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 list = new List(); 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(); 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 PhotoRecords = new List(); private static readonly Dictionary ById = new Dictionary(); private static readonly Dictionary ByToken = new Dictionary(); 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 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 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 FramePhotos = new Dictionary(); private static readonly Dictionary RemotePhotos = new Dictionary(); private static readonly Dictionary Textures = new Dictionary(); private static readonly Dictionary Receiving = new Dictionary(); private static readonly HashSet ReadyClients = new HashSet(); private static readonly Dictionary> SentPhotos = new Dictionary>(); 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(); } 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(); } 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[] 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(); 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(); 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 _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("Spawn", "Rarity", 65, "Relative spawn weight on all moons. 65 aims for a fairly common one or two frames per round."); ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind("Photos", "Folder", text, "Folder read only when this player is the host. Restart the game after changing photos."); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind("Photos", "MaximumDimension", 1024, "Maximum width or height after compression (256-2048)."); ConfigEntry val3 = ((BaseUnityPlugin)this).Config.Bind("Photos", "JpegQuality", 82, "JPEG compression quality (55-95)."); ConfigEntry val4 = ((BaseUnityPlugin)this).Config.Bind("Photos", "MaximumPhotos", 64, "Maximum number of files read from the host photo folder (1-128)."); ConfigEntry val5 = ((BaseUnityPlugin)this).Config.Bind("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(); ((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)Resources.FindObjectsOfTypeAll()).FirstOrDefault((Func)((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(); val4.mass = 1.15f; val4.drag = 0.08f; val4.angularDrag = 0.08f; BoxCollider val5 = val3.AddComponent(); val5.size = new Vector3(0.84f, 0.58f, 0.09f); PhotoFrameItem photoFrameItem = val3.AddComponent(); ((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(); GameObject val6 = new GameObject("ScanNode"); val6.layer = 22; val6.transform.SetParent(val3.transform, false); ScanNodeProperties val7 = val6.AddComponent(); 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(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } ((Renderer)val.GetComponent()).sharedMaterial = material; return val; } }