Decompiled source of PeakThings v0.1.11

plugins/PeakThings/PeakThings.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Evaisa.PeakThings.MonoBehaviours;
using Evaisa.PeakThings.Recorder;
using Evaisa.PeakThings.Recorder.CommandPackages;
using Evaisa.PeakThings.Recorder.ImageEncoding;
using Evaisa.PeakThings.extensions;
using Evaisa.PeakThings.hooks;
using Evaisa.PeakThings.modules;
using ExitGames.Client.Photon;
using HarmonyLib;
using IL.Photon.Voice.Unity;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice.Unity;
using TMPro;
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;
using UnityEngine.Video;
using Zorro.Core;
using Zorro.Core.Serizalization;
using Zorro.PhotonUtility;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Universal.Runtime")]
[assembly: AssemblyCompany("PeakThings")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dee5d4928f14ac4f1ee2fa917d4dce741520c1f1")]
[assembly: AssemblyProduct("PeakThings")]
[assembly: AssemblyTitle("PeakThings")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Evaisa.PeakThings
{
	internal class CustomPrefabPool : IPunPrefabPool
	{
		public readonly Dictionary<string, GameObject> Prefabs = new Dictionary<string, GameObject>();

		private DefaultPool? _defaultPool;

		public DefaultPool DefaultPool
		{
			get
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Expected O, but got Unknown
				if (_defaultPool == null)
				{
					_defaultPool = new DefaultPool();
				}
				return _defaultPool;
			}
			set
			{
				if (value != null)
				{
					_defaultPool = value;
				}
			}
		}

		public bool RegisterPrefab(string prefabId, GameObject prefab)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				throw new ArgumentException("CustomPrefabPool: failed to register network prefab. Prefab is null.");
			}
			if (string.IsNullOrWhiteSpace(prefabId))
			{
				throw new ArgumentException("CustomPrefabPool: failed to register network prefab. PrefabId is invalid.");
			}
			if (HasPrefab(prefabId))
			{
				PeakThings.Log.LogError((object)("CustomPrefabPool: failed to register network prefab \"" + prefabId + "\". Prefab already exists in Resources with the same prefab id."));
				return false;
			}
			if (Prefabs.TryGetValue(prefabId, out GameObject value, ignoreKeyCase: true))
			{
				LogLevel val = (LogLevel)(((Object)(object)value == (Object)(object)prefab) ? 4 : 2);
				PeakThings.Log.Log(val, (object)("CustomPrefabPool: failed to register network prefab \"" + prefabId + "\". There is already a prefab registered with the same prefab id."));
				return false;
			}
			Prefabs[prefabId] = prefab;
			PeakThings.Log.LogDebug((object)("CustomPrefabPool: registered network prefab \"" + prefabId + "\""));
			return true;
		}

		public bool HasPrefab(GameObject prefab)
		{
			if (Prefabs.ContainsValue(prefab))
			{
				return true;
			}
			return false;
		}

		public bool HasPrefab(string prefabId)
		{
			return (Object)(object)GetPrefab(prefabId) != (Object)null;
		}

		public string? GetPrefabId(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				PeakThings.Log.LogError((object)"Failed to get prefab id. GameObject is null.");
				return string.Empty;
			}
			return Prefabs.GetKeyOrDefault(prefab);
		}

		public GameObject? GetPrefab(string prefabId)
		{
			if (Prefabs.TryGetValue(prefabId, out GameObject value, ignoreKeyCase: true))
			{
				return value;
			}
			return Resources.Load<GameObject>(prefabId);
		}

		public GameObject? Instantiate(string prefabId, Vector3 position, Quaternion rotation)
		{
			//IL_002b: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(prefabId))
			{
				throw new ArgumentException("CustomPrefabPool: failed to spawn network prefab. PrefabId is null.");
			}
			GameObject val;
			if (!Prefabs.TryGetValue(prefabId, out GameObject value, ignoreKeyCase: true))
			{
				val = DefaultPool.Instantiate(prefabId, position, rotation);
				if ((Object)(object)val == (Object)null)
				{
					PeakThings.Log.LogError((object)("CustomPrefabPool: failed to spawn network prefab \"" + prefabId + "\". GameObject is null."));
				}
				return val;
			}
			bool activeSelf = value.activeSelf;
			if (activeSelf)
			{
				value.SetActive(false);
			}
			val = Object.Instantiate<GameObject>(value, position, rotation);
			if (activeSelf)
			{
				value.SetActive(true);
			}
			PeakThings.Log.LogInfo((object)$"CustomPrefabPool: spawned network prefab \"{prefabId}\" at position {position}, rotation {((Quaternion)(ref rotation)).eulerAngles}");
			return val;
		}

		public void Destroy(GameObject gameObject)
		{
			Object.Destroy((Object)(object)gameObject);
		}
	}
	[BepInPlugin("evaisa.PeakThings", "PeakThings", "0.1.11")]
	public class PeakThings : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <DelayedFunction>d__24 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Action action;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedFunction>d__24(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					action();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadBundleAsync>d__34 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string path;

			public PeakThings <>4__this;

			private AssetBundleCreateRequest <bundleRequest>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadBundleAsync>d__34(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<bundleRequest>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				PeakThings peakThings = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<bundleRequest>5__2 = AssetBundle.LoadFromFileAsync(path);
					<>2__current = <bundleRequest>5__2;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					Bundle = <bundleRequest>5__2.assetBundle;
					peakThings.Register();
					VideoCamera.SetupCameraControllers(((Component)peakThings).gameObject);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string GUID = "evaisa.PeakThings";

		public const string ModName = "PeakThings";

		public const string Version = "0.1.11";

		private bool patchedAwake;

		public Dictionary<string, GameObject> prefabs = new Dictionary<string, GameObject>();

		public Dictionary<string, string> translationsRealNotFake = new Dictionary<string, string>
		{
			{ "NAME_Camera", "Camera" },
			{ "NAME_ArsonItem", "Arson" },
			{ "NAME_TapeRecording", "Found Footage" },
			{ "Camera", "Camera" },
			{ "ArsonItem", "Arson" },
			{ "TapeRecording", "Found Footage" },
			{ "ToggleRecording", "Toggle Recording" },
			{ "FlipCamera", "Flip Camera" },
			{ "Zoom", "Zoom" },
			{ "Squeeze", "Squeeze!" },
			{ "DingusItem", "Dingus" },
			{ "Meow", "Meow" },
			{ "Toggle Music", "Toggle Music" }
		};

		public ConfigEntry<float> MaxRecordingTime;

		public ConfigEntry<bool> DisableFolderShortcuts;

		public ConfigEntry<KeyCode> TempFileFolderKey;

		public ConfigEntry<KeyCode> CompletedRecordingFolderKey;

		public bool spawnedStuffThisRun;

		public static PeakThings Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static AssetBundle Bundle { get; set; }

		private void Awake()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			LoadSettings();
			ItemCookingHooks.Setup();
			ItemHooks.Setup();
			GameHandler.Awake += new hook_Awake(GameHandler_Awake);
			Character.Update += new hook_Update(Character_Update);
			Mirror.Start += new hook_Start(Mirror_Start);
			RunManager.StartRun += new hook_StartRun(RunManager_StartRun);
			DataEntryValue.GetNewFromValue += new hook_GetNewFromValue(DataEntryValue_GetNewFromValue);
			DataEntryValue.GetTypeValue += new hook_GetTypeValue(DataEntryValue_GetTypeValue);
			InRoomState.Enter += new hook_Enter(InRoomState_Enter);
			MainMenu.Start += new hook_Start(MainMenu_Start);
			Log.LogInfo((object)"PeakThings is loaded!");
			MicWrapper.Read += new Manipulator(MicWrapper_Read);
			LocalizedText.LoadMainTable += new hook_LoadMainTable(LocalizedText_LoadMainTable);
		}

		public void LoadSettings()
		{
			MaxRecordingTime = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Max Recording Time", 180f, "Maximum recording time in seconds, -1 for unlimited.");
			DisableFolderShortcuts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Disable Folder Shortcuts", false, "Disable folder shortcuts for open recording folders.");
			TempFileFolderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "Temp Recording Folder Key", (KeyCode)284, "Key to open the temporary recordings folder.");
			CompletedRecordingFolderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "Completed Recording Folder Key", (KeyCode)287, "Key to open the completed recordings folder. (Cleared upon new run)");
		}

		[IteratorStateMachine(typeof(<DelayedFunction>d__24))]
		private IEnumerator DelayedFunction(Action action)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedFunction>d__24(0)
			{
				action = action
			};
		}

		private void MainMenu_Start(orig_Start orig, MainMenu self)
		{
			RetrievableSingleton<RecordingsHandler>.Instance.ClearRecordings();
			orig.Invoke(self);
		}

		private void LocalizedText_LoadMainTable(orig_LoadMainTable orig, bool forceSerialization)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(forceSerialization);
			foreach (Language value in Enum.GetValues(typeof(Language)))
			{
				foreach (KeyValuePair<string, string> item in translationsRealNotFake)
				{
					CreateLocalizationInternal(item.Key, item.Value, value);
				}
			}
		}

		internal static void CreateLocalizationInternal(string index, string translation, Language language)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected I4, but got Unknown
			string translation2 = translation;
			index = index.ToUpperInvariant();
			if (!LocalizedText.MAIN_TABLE.TryGetValue(index, out var value))
			{
				value = new List<string>();
				value.AddRange(from Language _ in Enum.GetValues(typeof(Language))
					select translation2);
				LocalizedText.MAIN_TABLE.Add(index, value);
			}
			else
			{
				value[(int)language] = translation2;
			}
		}

		private void MicWrapper_Read(ILContext il)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			MethodBody body = il.Body;
			ModuleDefinition module = ((MemberReference)body.Method).Module;
			VariableDefinition val = new VariableDefinition(module.ImportReference(typeof(RecorderAudioListener)));
			body.Variables.Add(val);
			body.InitLocals = true;
			MethodInfo getMethod = typeof(Singleton<RecorderAudioListener>).GetProperty("Instance").GetGetMethod();
			MethodInfo getMethod2 = typeof(MicWrapper).GetProperty("SamplingRate").GetGetMethod();
			MethodInfo getMethod3 = typeof(MicWrapper).GetProperty("Channels").GetGetMethod();
			MethodInfo method = typeof(RecorderAudioListener).GetMethod("SendMic", new Type[3]
			{
				typeof(float[]),
				typeof(int),
				typeof(int)
			});
			ILCursor val2 = new ILCursor(il);
			if (val2.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1]
			{
				(Instruction instr) => ILPatternMatchingExt.MatchCallvirt(instr, "Photon.Voice.Unity.MicrophoneRelay", "SendMic")
			}))
			{
				ILLabel val3 = val2.DefineLabel();
				val2.Emit(OpCodes.Call, module.ImportReference((MethodBase)getMethod));
				val2.Emit(OpCodes.Stloc, val);
				val2.Emit(OpCodes.Ldloc, val);
				val2.Emit(OpCodes.Brfalse_S, (object)val3);
				val2.Emit(OpCodes.Ldloc, val);
				val2.Emit(OpCodes.Ldarg_1);
				val2.Emit(OpCodes.Ldarg_0);
				val2.Emit(OpCodes.Callvirt, module.ImportReference((MethodBase)getMethod2));
				val2.Emit(OpCodes.Ldarg_0);
				val2.Emit(OpCodes.Callvirt, module.ImportReference((MethodBase)getMethod3));
				val2.Emit(OpCodes.Callvirt, module.ImportReference((MethodBase)method));
				val2.MarkLabel(val3);
			}
		}

		private void LoadItems()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			spawnedStuffThisRun = true;
			Log.LogInfo((object)"Attempting to load items.");
			RetrievableSingleton<RecordingsHandler>.Instance.ClearRecordings();
			if (PhotonNetwork.IsMasterClient && !(SceneManagerHelper.ActiveSceneName == "Airport"))
			{
				if (prefabs.ContainsKey("CamcorderItem"))
				{
					Transform transform = GameObject.Find("front half/Frame.007").transform;
					Instance.SpawnPrefab("CamcorderItem", transform.position + transform.forward * 1.2f + transform.right * 2.5f, Quaternion.LookRotation(-transform.right));
				}
				if (prefabs.ContainsKey("ArsonItem"))
				{
					Transform transform2 = GameObject.Find("Back Half/Frame.001").transform;
					Instance.SpawnPrefab("ArsonItem", transform2.position + transform2.forward * 1.2f + transform2.right * 0.2f, Quaternion.LookRotation(-transform2.right));
				}
			}
		}

		private void InRoomState_Enter(orig_Enter orig, InRoomState self)
		{
			orig.Invoke(self);
			Debug.Log((object)"InRoomState_Enter called, registering custom command packages.");
			CommandListener component = GameObject.Find("CustomCommandListener").GetComponent<CommandListener>();
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<StartRecordingCommandPackage>(new StartRecordingCommandPackage());
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<StopRecordingCommandPackage>(new StopRecordingCommandPackage());
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<SendVideoChunkPackage>(new SendVideoChunkPackage());
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<AddClipToShareQueuePackage>(new AddClipToShareQueuePackage());
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<ActivateNextSharingJobPackage>(new ActivateNextSharingJobPackage());
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<SendClipCompletedPackage>(new SendClipCompletedPackage());
			((CustomCommandListener<CustomCommandType>)(object)component).RegisterPackage<ReRequestClipPackage>(new ReRequestClipPackage());
		}

		private byte DataEntryValue_GetTypeValue(orig_GetTypeValue orig, Type type)
		{
			if (type == typeof(VideoInfoEntry))
			{
				return 53;
			}
			if (type == typeof(FlashcardEntry))
			{
				return 54;
			}
			return orig.Invoke(type);
		}

		private DataEntryValue DataEntryValue_GetNewFromValue(orig_GetNewFromValue orig, byte value)
		{
			return (DataEntryValue)(value switch
			{
				53 => new VideoInfoEntry(), 
				54 => new FlashcardEntry(), 
				_ => orig.Invoke(value), 
			});
		}

		[IteratorStateMachine(typeof(<LoadBundleAsync>d__34))]
		private IEnumerator LoadBundleAsync(string path)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadBundleAsync>d__34(0)
			{
				<>4__this = this,
				path = path
			};
		}

		private void RunManager_StartRun(orig_StartRun orig, RunManager self)
		{
			//IL_00ae: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			Log.LogInfo((object)"RunManager_StartRun");
			RecordingsHandler instance = RetrievableSingleton<RecordingsHandler>.Instance;
			PhotonSendVideoHandler instance2 = RetrievableSingleton<PhotonSendVideoHandler>.Instance;
			spawnedStuffThisRun = false;
			if (!PhotonNetwork.IsMasterClient || SceneManagerHelper.ActiveSceneName != "Airport")
			{
				if (SceneManagerHelper.ActiveSceneName.StartsWith("Level_") && PhotonNetwork.IsConnected && PhotonNetwork.IsMasterClient)
				{
					((MonoBehaviour)this).StartCoroutine(DelayedFunction(LoadItems));
				}
			}
			else
			{
				Log.LogInfo((object)"Spawning TVSet prefab");
				Vector3 position = default(Vector3);
				((Vector3)(ref position))..ctor(-15.29617f, 3.101736f, 106.5155f);
				Quaternion rotation = Quaternion.Euler(0f, 0f, 0f);
				SpawnPrefab("TVSet", position, rotation);
			}
		}

		public void RegisterPrefab(string id, string path)
		{
			if (prefabs.ContainsKey(id))
			{
				Log.LogWarning((object)("Prefab " + id + " is already registered."));
				return;
			}
			GameObject val = Bundle.LoadAsset<GameObject>(path);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)("Prefab " + id + " could not be loaded from path " + path + "."));
			}
			else
			{
				((Object)val).name = "PeakThings_" + ((Object)val).name;
				FixPrefabReferences(val);
				prefabs[id] = val;
				NetworkPrefabs.RegisterNetworkPrefab("0_Items/" + ((Object)val).name, val);
				Log.LogInfo((object)("Registered prefab " + ((Object)val).name + " from path " + path + "."));
			}
		}

		private void Mirror_Start(orig_Start orig, Mirror self)
		{
			Camera mirrorCamera = self.mirrorCamera;
			mirrorCamera.cullingMask |= 0x10000000;
			orig.Invoke(self);
		}

		public void Start()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			RenderPipelineAsset currentRenderPipeline = GraphicsSettings.currentRenderPipeline;
			UniversalRenderPipelineAsset val = (UniversalRenderPipelineAsset)(object)((currentRenderPipeline is UniversalRenderPipelineAsset) ? currentRenderPipeline : null);
			ScriptableRendererData obj = val.rendererDataList[0];
			UniversalRendererData val2 = (UniversalRendererData)(object)((obj is UniversalRendererData) ? obj : null);
			val2.transparentLayerMask = LayerMask.op_Implicit(LayerMask.op_Implicit(val2.transparentLayerMask) | 0x10000000);
			val2.opaqueLayerMask = LayerMask.op_Implicit(LayerMask.op_Implicit(val2.opaqueLayerMask) | 0x10000000);
			HelperFunctions.AllPhysical = LayerMask.op_Implicit(LayerMask.op_Implicit(HelperFunctions.AllPhysical) | 0x10000000);
			HelperFunctions.AllPhysicalExceptCharacter = LayerMask.op_Implicit(LayerMask.op_Implicit(HelperFunctions.AllPhysicalExceptCharacter) | 0x10000000);
			HelperFunctions.DefaultMask = LayerMask.op_Implicit(LayerMask.op_Implicit(HelperFunctions.DefaultMask) | 0x10000000);
		}

		public void Register()
		{
			RegisterPrefab("CamcorderItem", "Assets/Custom/PeakThings/Items/Camcorder/CamcorderItem.prefab");
			RegisterPrefab("ArsonItem", "Assets/Custom/PeakThings/Items/Arson/ArsonItem.prefab");
			RegisterPrefab("TVSet", "Assets/Custom/PeakThings/Lobby/TVSet.prefab");
			RegisterPrefab("TapeRecording", "Assets/Custom/PeakThings/Items/Tape/TapeRecording.prefab");
			RegisterPrefab("Dingus", "Assets/Custom/PeakThings/Items/Dingus/Dingus.prefab");
			RegisterItem(prefabs["CamcorderItem"].GetComponent<Item>());
			RegisterItem(prefabs["ArsonItem"].GetComponent<Item>());
			RegisterItem(prefabs["TapeRecording"].GetComponent<Item>());
			RegisterItem(prefabs["Dingus"].GetComponent<Item>());
		}

		private void RegisterItem(Item item)
		{
			ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance;
			byte[] value = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("evaisa.PeakThings" + ((Object)item).name));
			ushort key = (item.itemID = BitConverter.ToUInt16(value, 0));
			((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects.Add(item);
			instance.itemLookup.Add(key, item);
		}

		private void GameHandler_Awake(orig_Awake orig, GameHandler self)
		{
			orig.Invoke(self);
			if (!patchedAwake)
			{
				Log.LogInfo((object)"Patching GameHandler.Awake");
				patchedAwake = true;
				NetworkPrefabs.Initialize();
				string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "peakthings");
				((MonoBehaviour)this).StartCoroutine(LoadBundleAsync(path));
			}
		}

		private static Texture2D CreateReadableRGBA32(Texture2D src)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)src).width, ((Texture)src).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0);
			Graphics.Blit((Texture)(object)src, temporary);
			RenderTexture active = RenderTexture.active;
			RenderTexture.active = temporary;
			Texture2D val = new Texture2D(((Texture)src).width, ((Texture)src).height, (TextureFormat)4, false);
			val.ReadPixels(new Rect(0f, 0f, (float)((Texture)temporary).width, (float)((Texture)temporary).height), 0, 0);
			val.Apply();
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			return val;
		}

		public void FixPrefabReferences(GameObject prefab)
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			Shader shader = Shader.Find("W/Peak_Standard");
			Shader shader2 = Shader.Find("W/Peak_Transparent");
			Shader shader3 = Shader.Find("Universal Render Pipeline/Lit");
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] materials = val.materials;
				foreach (Material val2 in materials)
				{
					if (((Object)val2.shader).name == "W/Peak_Standard")
					{
						val2.shader = shader;
					}
					else if (((Object)val2.shader).name == "W/Peak_Transparent")
					{
						val2.shader = shader2;
					}
					else
					{
						val2.shader = shader3;
					}
				}
			}
			foreach (Material item in prefab.GetComponentsInChildren<Renderer>(true).SelectMany((Renderer r) => r.materials))
			{
				if (!item.HasProperty("_BaseTexture"))
				{
					continue;
				}
				Texture texture = item.GetTexture("_BaseTexture");
				Texture2D val3 = (Texture2D)(object)((texture is Texture2D) ? texture : null);
				if ((Object)(object)val3 != (Object)null)
				{
					Texture2D val4 = CreateReadableRGBA32(val3);
					Color[] pixels = val4.GetPixels();
					for (int k = 0; k < pixels.Length; k++)
					{
						ref Color reference = ref pixels[k];
						reference *= 1.2f;
					}
					val4.SetPixels(pixels);
					val4.Apply();
					item.SetTexture("_BaseTexture", (Texture)(object)val4);
				}
			}
			Shader shader4 = Shader.Find("Shader Graphs/Decal");
			DecalProjector[] componentsInChildren2 = prefab.GetComponentsInChildren<DecalProjector>(true);
			foreach (DecalProjector val5 in componentsInChildren2)
			{
				val5.material.shader = shader4;
				Log.LogInfo((object)("Fixed decal shader for " + ((Object)val5).name + " in prefab " + ((Object)prefab).name + "."));
			}
			ParticleSystem[] componentsInChildren3 = prefab.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val6 in componentsInChildren3)
			{
				ParticleSystemRenderer component = ((Component)val6).GetComponent<ParticleSystemRenderer>();
				if ((Object)(object)component != (Object)null && (Object)(object)((Renderer)component).material != (Object)null && ((Object)((Renderer)component).material).name.Contains("Smoke"))
				{
					((Renderer)component).material = ((IEnumerable<Material>)Resources.FindObjectsOfTypeAll<Material>()).FirstOrDefault((Func<Material, bool>)((Material x) => ((Object)x).name == "Smoke"));
				}
			}
			TextMeshProUGUI[] componentsInChildren4 = prefab.GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val7 in componentsInChildren4)
			{
				((TMP_Text)val7).font = Resources.Load<TMP_FontAsset>("Font/DarumaDropOne-Regular SDF");
			}
		}

		private void Character_Update(orig_Update orig, Character character)
		{
			orig.Invoke(character);
		}

		internal GameObject SpawnPrefab(string id, Vector3 position, Quaternion rotation)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient)
			{
				return null;
			}
			if (!prefabs.ContainsKey(id))
			{
				return null;
			}
			string name = ((Object)prefabs[id]).name;
			string text = "0_Items/" + name;
			if (!NetworkPrefabs.TryGetNetworkPrefab(text, out GameObject _))
			{
				Log.LogError((object)("Failed to spawn prefab " + text + ". Prefab not found."));
				return null;
			}
			try
			{
				GameObject result = PhotonNetwork.Instantiate(text, position, rotation, (byte)0, (object[])null);
				Log.LogInfo((object)$"Spawned prefab {text} at {position} with rotation {rotation}.");
				return result;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Error spawning prefab " + name + ": " + ex.Message));
			}
			return null;
		}

		internal GameObject SpawnPrefab(string id, Character character)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient)
			{
				return null;
			}
			Vector3 val = character.Center + Vector3.up * 1f + Random.insideUnitSphere * 1.5f;
			val.y = Mathf.Max(val.y, character.Center.y);
			Quaternion rotation = Quaternion.Euler(0f, 0f, 0f);
			return SpawnPrefab(id, val, rotation);
		}
	}
	public static class EnumerableExtensions
	{
		public static void ForEachTry<T>(this IEnumerable<T> list, Action<T> action, IDictionary<T, Exception> exceptions = null)
		{
			Action<T> action2 = action;
			IDictionary<T, Exception> exceptions2 = exceptions;
			list.ToList().ForEach(delegate(T element)
			{
				try
				{
					action2(element);
				}
				catch (Exception value)
				{
					exceptions2?.Add(element, value);
				}
			});
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "PeakThings";

		public const string PLUGIN_NAME = "PeakThings";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace Evaisa.PeakThings.Recorder
{
	public class AudioData
	{
		public float[] Data;

		public AudioData(float[] data)
		{
			Data = data;
		}
	}
	public class CameraHandler : Singleton<CameraHandler>
	{
		private Dictionary<Guid, VideoCamera> m_cameras = new Dictionary<Guid, VideoCamera>();

		public static void RegisterCamera(Guid id, VideoCamera camera)
		{
			PeakThings.Log.LogInfo((object)$"Registering camera with ID: {id}");
			if ((Object)(object)Singleton<CameraHandler>.Instance != (Object)null)
			{
				Singleton<CameraHandler>.Instance.m_cameras.Add(id, camera);
				PeakThings.Log.LogInfo((object)("Camera registered successfully: " + ((Object)camera).name));
			}
		}

		public static void UnregisterCamera(Guid id)
		{
			if ((Object)(object)Singleton<CameraHandler>.Instance != (Object)null)
			{
				Singleton<CameraHandler>.Instance.m_cameras.Remove(id);
			}
		}

		public static bool TryGetCamera(Guid instanceDataGuid, out VideoCamera videoCamera)
		{
			if ((Object)(object)Singleton<CameraHandler>.Instance == (Object)null)
			{
				videoCamera = null;
				return false;
			}
			return Singleton<CameraHandler>.Instance.m_cameras.TryGetValue(instanceDataGuid, out videoCamera);
		}
	}
	public class CameraRecording : MonoBehaviour, IPlayableVideo
	{
		public VideoHandle videoHandle;

		private List<Clip> m_clips;

		public DateTime m_lastModified;

		public int ClipCount => m_clips.Count;

		public DateTime LastModified => m_lastModified;

		public bool ReadyToExtract(out string failureReason)
		{
			int clipCount = ClipCount;
			failureReason = $"video={videoHandle.id}:";
			bool result = true;
			for (int i = 0; i < clipCount; i++)
			{
				Clip clip = GetClip(i);
				if (!clip.Valid)
				{
					continue;
				}
				if (clip.isRecording)
				{
					failureReason += $" clip {i} of {clipCount} ({clip.clipID.id}) still recording!";
					result = false;
					continue;
				}
				if (clip.local && !clip.encoded)
				{
					failureReason += $" clip {i} of {clipCount} ({clip.clipID.id}) is local but not encoded!";
					result = false;
				}
				if (!clip.local && !clip.hasBeenRecieved)
				{
					failureReason += $" clip {i} of {clipCount} ({clip.clipID.id}) is from another player but not downloaded!";
					result = false;
				}
			}
			return result;
		}

		public void SetInfo(VideoHandle videoID)
		{
			videoHandle = videoID;
			m_clips = new List<Clip>();
		}

		public void AddNewClip(Clip clip)
		{
			m_lastModified = DateTime.Now;
			m_clips.Add(clip);
			Debug.Log((object)$"video {GuidExtensions.ToShortString(videoHandle.id)} added new clip: {clip.clipID.ToShortString()}, total clips: {m_clips.Count}");
		}

		public Clip EndCurrentClip()
		{
			if (m_clips.Count == 0)
			{
				Debug.LogWarning((object)"No clips to end");
				return null;
			}
			List<Clip> clips = m_clips;
			Clip clip = clips[clips.Count - 1];
			clip.EndClip();
			return clip;
		}

		public Clip GetClip(int i)
		{
			return m_clips[i];
		}

		public string GetDirectory()
		{
			return Path.Combine(RecordingsHandler.GetDirectory(), videoHandle.id.ToString());
		}

		public List<Clip> GetAllClips()
		{
			return m_clips;
		}

		public bool TryGetLatestClip(out Clip clip)
		{
			if (m_clips.Count > 0)
			{
				List<Clip> clips = m_clips;
				clip = clips[clips.Count - 1];
				return true;
			}
			clip = null;
			return false;
		}

		public bool SaveToDesktop(out string videoFileName)
		{
			if (!RecordingsHandler.TryGetRecordingPath(videoHandle, out string path))
			{
				videoFileName = string.Empty;
				return false;
			}
			videoFileName = "content_warning_" + GuidExtensions.ToShortString(videoHandle.id) + ".webm";
			string destFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), videoFileName);
			if (!File.Exists(path))
			{
				Debug.LogError((object)("Video: " + path + " Does Not Exist!"));
				return false;
			}
			File.Copy(path, destFileName);
			return true;
		}

		public bool TryGetClip(ClipID clipID, out Clip clip)
		{
			foreach (Clip clip2 in m_clips)
			{
				if (clipID.Equals(clip2.clipID))
				{
					clip = clip2;
					return true;
				}
			}
			clip = null;
			return false;
		}

		public bool TryGetVideoPath(out string path)
		{
			return RecordingsHandler.TryGetRecordingPath(videoHandle, out path);
		}
	}
	[Serializable]
	public class Clip
	{
		public CameraRecording m_recording;

		public ClipID clipID;

		public bool local;

		public int ownerID;

		public bool isRecording;

		public bool encoded;

		public bool hasBeenRecieved;

		public float m_timeStarted;

		public float m_timeEnded;

		private VideoRecorder m_recorder;

		public bool Valid { get; protected set; }

		public float ClipLength => m_timeEnded - m_timeStarted;

		public Clip(ClipID clipID, bool local, int ownerID, CameraRecording recording)
		{
			this.ownerID = ownerID;
			this.clipID = clipID;
			this.local = local;
			isRecording = true;
			m_recording = recording;
			m_timeStarted = Time.time;
			Valid = true;
		}

		public void EndClip()
		{
			m_timeEnded = Time.time;
			isRecording = false;
			if ((Object)(object)m_recorder != (Object)null && !m_recorder.HasRecorded)
			{
				Debug.LogError((object)"Clip: CLIP HAS NO FRAMES!");
			}
			PeakThings.Log.LogInfo((object)("Ended clip: " + clipID.ToShortString()));
		}

		public void SetRecorder(VideoRecorder recorder)
		{
			m_recorder = recorder;
		}

		public VideoRecorder GetRecorder()
		{
			return m_recorder;
		}

		public string GetClipDirectory()
		{
			return Path.Combine(m_recording.GetDirectory(), clipID.id.ToString());
		}

		public void SetValid(bool validClip)
		{
			Valid = validClip;
		}
	}
	public struct ClipID : IComparable<ClipID>, IEquatable<ClipID>
	{
		public Guid id;

		public ClipID(Guid id)
		{
			this.id = id;
		}

		public int CompareTo(ClipID other)
		{
			return id.CompareTo(other.id);
		}

		public bool Equals(ClipID other)
		{
			return id.Equals(other.id);
		}

		public override string ToString()
		{
			return id.ToString();
		}

		public string ToShortString()
		{
			return id.ToString().Substring(0, 8);
		}

		public string ToMiniString()
		{
			return id.ToString().Substring(0, 3);
		}
	}
	public enum FfmpegDeadline
	{
		None,
		Realtime
	}
	public class FfmpegEncoder
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass5_0
		{
			public Task<string> outputTask;

			internal bool <RunFfmpeg>b__0()
			{
				return outputTask.IsCompleted;
			}
		}

		[CompilerGenerated]
		private sealed class <Encode>d__3 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public FfmpegEncoder <>4__this;

			public bool mic;

			public byte framerate;

			public FfmpegDeadline deadline;

			public bool displayWindow;

			private DirectoryInfo <directory>5__2;

			private int <audioSampleRate>5__3;

			private int <micSampleRate>5__4;

			private int <micChannels>5__5;

			private string <fullAudioPath>5__6;

			private string <fullMicAudioPath>5__7;

			private int <frameCount>5__8;

			private float <duration>5__9;

			private string <outputPath>5__10;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Encode>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<directory>5__2 = null;
				<fullAudioPath>5__6 = null;
				<fullMicAudioPath>5__7 = null;
				<outputPath>5__10 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fa: Expected O, but got Unknown
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				FfmpegEncoder ffmpegEncoder = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<directory>5__2 = ffmpegEncoder.m_session.Pipe.GetDirectory();
					<audioSampleRate>5__3 = AudioSettings.outputSampleRate;
					<micSampleRate>5__4 = 24000;
					<micChannels>5__5 = 2;
					if (ffmpegEncoder.m_session.MicSampleRate.IsSome)
					{
						<micSampleRate>5__4 = ffmpegEncoder.m_session.MicSampleRate.Value;
					}
					if (ffmpegEncoder.m_session.MicChannels.IsSome)
					{
						<micChannels>5__5 = ffmpegEncoder.m_session.MicChannels.Value;
					}
					<fullAudioPath>5__6 = ffmpegEncoder.m_session.GetAudioPath();
					<fullMicAudioPath>5__7 = ffmpegEncoder.m_session.GetMicAudioPath();
					ffmpegEncoder.SaveAudioBlobs(mic);
					<>2__current = (object)new WaitForSecondsRealtime(0.1f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					<frameCount>5__8 = <directory>5__2.GetFiles().Length;
					<duration>5__9 = (float)<frameCount>5__8 / (float)(int)framerate;
					List<string> list = new List<string>();
					string item = <directory>5__2.FullName + "/Test%04d.png";
					<outputPath>5__10 = <directory>5__2.FullName + "/output.webm";
					string item2 = "24000";
					list.Add("-y");
					list.Add("-thread_queue_size");
					list.Add("512");
					list.Add("-r");
					list.Add(framerate.ToString());
					list.Add("-i");
					list.Add(item);
					if (!string.IsNullOrEmpty(<fullAudioPath>5__6))
					{
						list.Add("-f");
						list.Add("f32le");
						list.Add("-ac");
						list.Add("2");
						list.Add("-ar");
						list.Add(<audioSampleRate>5__3.ToString());
						list.Add("-thread_queue_size");
						list.Add("512");
						list.Add("-i");
						list.Add(<fullAudioPath>5__6);
					}
					if (mic)
					{
						list.Add("-f");
						list.Add("f32le");
						list.Add("-ac");
						list.Add(<micChannels>5__5.ToString());
						list.Add("-ar");
						list.Add(<micSampleRate>5__4.ToString());
						list.Add("-thread_queue_size");
						list.Add("512");
						list.Add("-i");
						list.Add(<fullMicAudioPath>5__7);
					}
					if (!string.IsNullOrEmpty(<fullAudioPath>5__6))
					{
						list.Add("-map");
						list.Add("0:0");
						list.Add("-map");
						list.Add("1:0");
						list.Add("-c:a");
						list.Add("libvorbis");
						list.Add("-ac");
						list.Add("2");
						list.Add("-ar");
						list.Add(item2);
						if (mic)
						{
							list.Add("-filter_complex");
							list.Add("amix=inputs=2");
						}
					}
					list.Add("-c:v");
					list.Add("libvpx");
					list.Add("-cpu-used");
					list.Add("-5");
					if (deadline == FfmpegDeadline.Realtime)
					{
						list.Add("-deadline");
						list.Add("realtime");
					}
					list.Add("-pix_fmt");
					list.Add("yuv420p");
					list.Add("-speed");
					list.Add("1");
					list.Add("-preset");
					list.Add("ultrafast");
					list.Add(<outputPath>5__10);
					<>2__current = ffmpegEncoder.RunFfmpeg(list, displayWindow);
					<>1__state = 2;
					return true;
				}
				case 2:
				{
					<>1__state = -1;
					float num2 = (float)(ffmpegEncoder.m_session.AudioFrames * ffmpegEncoder.m_session.AudioDataSize) / ((float)AudioSettings.outputSampleRate * 2f);
					Debug.Log((object)$"Encoded {<directory>5__2.FullName}, {<frameCount>5__8} frames, Audio Frames {ffmpegEncoder.m_session.AudioFrames}, Audio Data Size {ffmpegEncoder.m_session.AudioDataSize}, Audio Duration {num2:F}s, Video Duration {<duration>5__9:F}s");
					if (!File.Exists(<outputPath>5__10))
					{
						if (ffmpegEncoder.ErrorTitle == null)
						{
							ffmpegEncoder.ErrorTitle = "Encode FAIL, Video path not found";
							ffmpegEncoder.ErrorBody = <outputPath>5__10;
						}
						Debug.LogError((object)("Encode FAIL, Video path not found" + <outputPath>5__10));
					}
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <RunFfmpeg>d__5 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public List<string> arguments;

			public bool displayWindow;

			public FfmpegEncoder <>4__this;

			private <>c__DisplayClass5_0 <>8__1;

			private Stopwatch <stopwatch>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RunFfmpeg>d__5(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<stopwatch>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f8: Expected O, but got Unknown
				int num = <>1__state;
				FfmpegEncoder ffmpegEncoder = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass5_0();
					Debug.Log((object)("Running FFmpeg encode... " + string.Join(" ", arguments)));
					<stopwatch>5__2 = new Stopwatch();
					<stopwatch>5__2.Start();
					ProcessStartInfo processStartInfo = new ProcessStartInfo
					{
						FileName = ExecutablePath,
						UseShellExecute = displayWindow,
						CreateNoWindow = !displayWindow,
						RedirectStandardInput = false,
						RedirectStandardOutput = false,
						RedirectStandardError = true
					};
					foreach (string argument in arguments)
					{
						processStartInfo.ArgumentList.Add(argument);
					}
					try
					{
						ffmpegEncoder.m_ffmpegProcess = Process.Start(processStartInfo);
					}
					catch (Exception ex)
					{
						Debug.LogException(ex);
						Debug.LogError((object)"Process.Start threw exception, see above (as a result, we probably failed to encode)");
						ffmpegEncoder.ErrorTitle = "Failed to start ffmpeg to encode video";
						if (ex is Win32Exception ex2 && ex2.ToString().Contains("Access is denied"))
						{
							ffmpegEncoder.ErrorTitle += " (Access is denied)";
						}
						ffmpegEncoder.ErrorBody = ex.ToString();
						return false;
					}
					if (ffmpegEncoder.m_ffmpegProcess == null)
					{
						Debug.LogError((object)"Process.Start returned null (as a result, we probably failed to encode)");
						ffmpegEncoder.ErrorTitle = "Failed to start ffmpeg to encode video";
						ffmpegEncoder.ErrorBody = "Process.Start returned null";
						return false;
					}
					<>8__1.outputTask = ffmpegEncoder.m_ffmpegProcess.StandardError.ReadToEndAsync();
					goto IL_01bd;
				}
				case 1:
					<>1__state = -1;
					goto IL_01bd;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_01bd:
					if (!ffmpegEncoder.m_ffmpegProcess.HasExited)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					if (!<>8__1.outputTask.IsCompleted)
					{
						<>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.outputTask.IsCompleted));
						<>1__state = 2;
						return true;
					}
					break;
				}
				string result = <>8__1.outputTask.Result;
				<stopwatch>5__2.Stop();
				Debug.Log((object)$"FFmpeg took {<stopwatch>5__2.Elapsed.TotalSeconds:F3}s to encode the video.");
				if (!string.IsNullOrWhiteSpace(result))
				{
					Debug.Log((object)$"Encoder FFmpeg stderr (exit code {ffmpegEncoder.m_ffmpegProcess.ExitCode}) {result}");
				}
				ffmpegEncoder.m_ffmpegProcess.Dispose();
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private Process m_ffmpegProcess;

		private RecordingSession m_session;

		public string ErrorTitle;

		public string ErrorBody;

		public static string ExecutablePath
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Invalid comparison between Unknown and I4
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Invalid comparison between Unknown and I4
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Invalid comparison between Unknown and I4
				RuntimePlatform platform = Application.platform;
				if ((int)platform > 1)
				{
					if ((int)platform == 13 || (int)platform == 16)
					{
						return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ffmpeg");
					}
					return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ffmpeg.exe");
				}
				return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "ffmpeg");
			}
		}

		public FfmpegEncoder(RecordingSession session)
		{
			m_session = session;
		}

		[IteratorStateMachine(typeof(<Encode>d__3))]
		public IEnumerator Encode(byte framerate, FfmpegDeadline deadline, bool displayWindow, bool mic)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Encode>d__3(0)
			{
				<>4__this = this,
				framerate = framerate,
				deadline = deadline,
				displayWindow = displayWindow,
				mic = mic
			};
		}

		private void SaveAudioBlobs(bool saveMic)
		{
			m_session.Pipe.GetDirectory().Create();
			byte[] audioBlob = m_session.GetAudioBlob();
			string audioPath = m_session.GetAudioPath();
			try
			{
				if (audioBlob != null)
				{
					File.WriteAllBytes(audioPath, audioBlob);
				}
				if (saveMic)
				{
					byte[] micAudioBlob = m_session.GetMicAudioBlob();
					string micAudioPath = m_session.GetMicAudioPath();
					if (micAudioBlob != null)
					{
						File.WriteAllBytes(micAudioPath, micAudioBlob);
					}
				}
			}
			catch (IOException ex) when (ex.HResult == -2147024784)
			{
				Debug.LogException((Exception)ex);
				Debug.LogError((object)"Failed to write to disk due to the above exception");
				ErrorTitle = "Disk full";
				ErrorBody = "Recording failed due to full disk. Please clear out your disk and restart the game.\n" + ex.Message;
			}
			catch (Exception ex2)
			{
				Debug.LogException(ex2);
				Debug.LogError((object)"Failed to write to disk due to the above exception");
				ErrorTitle = "Failed to write camera recording image to disk";
				ErrorBody = ex2.ToString();
			}
		}

		[IteratorStateMachine(typeof(<RunFfmpeg>d__5))]
		private IEnumerator RunFfmpeg(List<string> arguments, bool displayWindow)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RunFfmpeg>d__5(0)
			{
				<>4__this = this,
				arguments = arguments,
				displayWindow = displayWindow
			};
		}
	}
	public static class FFmpegStitcher
	{
		public static void StichVideos(string[] videos, string outputDirectory)
		{
			string text = Path.Combine(outputDirectory, "videoList.txt");
			string item = Path.Combine(outputDirectory, "fullRecording.webm");
			string text2 = "";
			foreach (string text3 in videos)
			{
				if (text3.Contains('\''))
				{
					Debug.LogWarning((object)("Video path contains single quote character \"'\", will attempt to escape it: " + text3));
				}
				text2 = text2 + "file '" + text3.Replace("'", "'\\''") + "'\n";
				if (!File.Exists(text3))
				{
					Debug.LogError((object)("Video File Not Found: " + text3));
				}
			}
			File.WriteAllText(text, text2);
			Debug.Log((object)("Stitching videos together: " + text2));
			ProcessStartInfo processStartInfo = new ProcessStartInfo
			{
				FileName = FfmpegEncoder.ExecutablePath,
				UseShellExecute = false,
				RedirectStandardOutput = false,
				RedirectStandardError = true,
				CreateNoWindow = true
			};
			processStartInfo.ArgumentList.Add("-y");
			processStartInfo.ArgumentList.Add("-f");
			processStartInfo.ArgumentList.Add("concat");
			processStartInfo.ArgumentList.Add("-safe");
			processStartInfo.ArgumentList.Add("0");
			processStartInfo.ArgumentList.Add("-i");
			processStartInfo.ArgumentList.Add(text);
			processStartInfo.ArgumentList.Add("-c");
			processStartInfo.ArgumentList.Add("copy");
			processStartInfo.ArgumentList.Add(item);
			Debug.Log((object)("Starting FFmpegStitcher: " + string.Join(" ", processStartInfo.ArgumentList)));
			Process process = Process.Start(processStartInfo);
			if (process == null)
			{
				Debug.LogError((object)"Video stitch ffmpeg Process.Start returned null");
				return;
			}
			string arg = process.StandardError.ReadToEnd();
			process.WaitForExit();
			Debug.Log((object)$"Video stitch ffmpeg stderr (exit code {process.ExitCode}): {arg}");
		}
	}
	public class FlashcardEntry : DataEntryValue
	{
		public VideoHandle videoID;

		public string title = "Found Footage";

		public override void SerializeValue(BinarySerializer serializer)
		{
			serializer.WriteGuid(videoID.id);
			serializer.WriteString(title, Encoding.UTF8);
		}

		public override void DeserializeValue(BinaryDeserializer deserializer)
		{
			videoID = new VideoHandle(deserializer.ReadGuid());
			title = deserializer.ReadString(Encoding.UTF8);
		}
	}
	public interface IPlayableVideo
	{
		bool TryGetVideoPath(out string path);
	}
	public class PngEncodeJobHandle
	{
		public JobHandle JobHandle;

		public NativeList<byte> OutputBuffer;

		public PngEncodeJobHandle(JobHandle jobHandle, NativeList<byte> outputBuffer)
		{
			//IL_0007: 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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			JobHandle = jobHandle;
			OutputBuffer = outputBuffer;
		}
	}
	public class QueuedFrame
	{
		public RenderTexture Frame;

		public AsyncGPUReadbackRequest ReadbackRequest;

		public QueuedFrame(RenderTexture frame, AsyncGPUReadbackRequest readbackRequest)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Frame = frame;
			ReadbackRequest = readbackRequest;
		}
	}
	public class RecorderAudioListener : Singleton<RecorderAudioListener>
	{
		private VideoRecorder m_videoRecorder;

		private void OnAudioFilterRead(float[] data, int channels)
		{
			try
			{
				if ((Object)(object)m_videoRecorder != (Object)null)
				{
					m_videoRecorder.AudioRead(data);
				}
			}
			catch (Exception ex)
			{
				Debug.Log((object)ex.ToString());
			}
		}

		public void SendAudioTo(VideoRecorder recorder)
		{
			Debug.Log((object)("Setting camera to send audio to " + (((Object)(object)recorder == (Object)null) ? "null" : ((Object)recorder).name)));
			m_videoRecorder = recorder;
		}

		public void RemoveRecorder(VideoRecorder recorder)
		{
			if ((Object)(object)m_videoRecorder == (Object)(object)recorder)
			{
				m_videoRecorder = null;
			}
		}

		public void SendMic(float[] buffer, int sampleRate, int channels)
		{
			if ((Object)(object)m_videoRecorder != (Object)null)
			{
				m_videoRecorder.PushMicData(CanRecordMic() ? buffer : new float[buffer.Length], sampleRate, channels);
			}
		}

		public virtual bool CanRecordMic()
		{
			return true;
		}
	}
	public class RecordingPipe : IDisposable
	{
		private uint m_width;

		private uint m_height;

		private int m_frameCount;

		private Queue<PngEncodeJobHandle> m_encodePngJobHandles;

		private ProfilerMarker m_flushMarker = new ProfilerMarker("RecordingPipe.Flush");

		private static string tempPath;

		private string path;

		private static string ErrorTitle;

		private static string ErrorBody;

		public DirectoryInfo GetDirectory()
		{
			return new DirectoryInfo(path);
		}

		public RecordingPipe(uint width, uint height, string directory)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			path = directory;
			m_width = width;
			m_height = height;
			m_frameCount = 0;
			if (GetDirectory().Exists)
			{
				GetDirectory().Delete(recursive: true);
			}
			m_encodePngJobHandles = new Queue<PngEncodeJobHandle>(3);
		}

		public void Dispose()
		{
		}

		public void Flush()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			AutoScope val = ((ProfilerMarker)(ref m_flushMarker)).Auto();
			try
			{
				if (m_encodePngJobHandles.Count > 0 && ((JobHandle)(ref m_encodePngJobHandles.Peek().JobHandle)).IsCompleted)
				{
					FlushLastHandle();
				}
			}
			finally
			{
				((IDisposable)(AutoScope)(ref val)).Dispose();
			}
		}

		private void FlushLastHandle()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			DirectoryInfo directory = GetDirectory();
			PngEncodeJobHandle pngEncodeJobHandle = m_encodePngJobHandles.Dequeue();
			((JobHandle)(ref pngEncodeJobHandle.JobHandle)).Complete();
			NativeList<byte> outputBuffer = pngEncodeJobHandle.OutputBuffer;
			byte[] array = new byte[outputBuffer.Length];
			new NativeSlice<byte>(NativeList<byte>.op_Implicit(outputBuffer)).CopyTo(array);
			outputBuffer.Dispose();
			string text = m_frameCount.ToString();
			int num = 4;
			if (text.Length < num)
			{
				text = text.PadLeft(num, '0');
			}
			string text2 = "Test" + text + ".png";
			try
			{
				File.WriteAllBytes(directory.FullName + "/" + text2, array);
			}
			catch (IOException ex) when (ex.HResult == -2147024784)
			{
				Debug.LogException((Exception)ex);
				Debug.LogError((object)"Failed to write to disk due to the above exception");
				ErrorTitle = "Disk full";
				ErrorBody = "Recording failed due to full disk. Please clear out your disk and restart the game.\n" + ex.Message;
			}
			catch (Exception ex2)
			{
				Debug.LogException(ex2);
				Debug.LogError((object)"Failed to write to disk due to the above exception");
				ErrorTitle = "Failed to write camera recording image to disk";
				ErrorBody = ex2.ToString();
			}
			m_frameCount++;
		}

		public void PushFrameData(NativeArray<byte> getData)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			DirectoryInfo directory = GetDirectory();
			if (!directory.Exists)
			{
				directory.Create();
			}
			NativeArray<byte> input = default(NativeArray<byte>);
			input..ctor(getData.Length, (Allocator)4, (NativeArrayOptions)1);
			NativeList<byte> val = default(NativeList<byte>);
			val..ctor(AllocatorHandle.op_Implicit((Allocator)4));
			input.CopyFrom(getData);
			getData.Dispose();
			EncodePngJob encodePngJob = default(EncodePngJob);
			encodePngJob.Input = input;
			encodePngJob.Output = val;
			encodePngJob.Width = m_width;
			encodePngJob.Height = m_height;
			EncodePngJob encodePngJob2 = encodePngJob;
			if (m_encodePngJobHandles.Count > 3)
			{
				FlushLastHandle();
			}
			m_encodePngJobHandles.Enqueue(new PngEncodeJobHandle(IJobExtensions.Schedule<EncodePngJob>(encodePngJob2, default(JobHandle)), val));
		}

		public static bool CheckErrorPopup(out string title, out string body)
		{
			title = ErrorTitle;
			body = ErrorBody;
			ErrorTitle = null;
			ErrorBody = null;
			return title != null;
		}
	}
	public class RecordingSession : IDisposable
	{
		private RecordingPipe m_pipe;

		private NativeList<float> m_audioData;

		private NativeList<float> m_micAudioData;

		private Material m_blitMaterial;

		private Queue<AsyncGPUReadbackRequest> _readbackQueue = new Queue<AsyncGPUReadbackRequest>(4);

		private ProfilerMarker m_processQueueMarker = new ProfilerMarker("RecordingSession.ProcessQueue");

		private ProfilerMarker m_queueFrameMarker = new ProfilerMarker("RecordingSession.QueueFrame");

		public int Frames { get; set; }

		public int AudioFrames { get; private set; }

		public int MicAudioFrames { get; private set; }

		public int AudioDataSize { get; set; }

		public int MicAudioDataSize { get; set; }

		public Optionable<int> MicSampleRate { get; set; }

		public Optionable<int> MicChannels { get; set; }

		public RecordingPipe Pipe => m_pipe;

		public RecordingSession(uint width, uint height, string directory)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//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_0067: Unknown result type (might be due to invalid IL or missing references)
			m_pipe = new RecordingPipe(width, height, directory);
			m_audioData = new NativeList<float>(100000, AllocatorHandle.op_Implicit((Allocator)4));
			m_micAudioData = new NativeList<float>(100000, AllocatorHandle.op_Implicit((Allocator)4));
			AudioFrames = 0;
		}

		public void PushFrame(RenderTexture frame)
		{
			if (m_pipe != null)
			{
				m_pipe.Flush();
				ProcessQueue();
				if ((Object)(object)frame != (Object)null)
				{
					QueueFrame(frame);
				}
			}
		}

		private void QueueFrame(RenderTexture frame)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			AutoScope val = ((ProfilerMarker)(ref m_queueFrameMarker)).Auto();
			try
			{
				if (_readbackQueue.Count <= 6)
				{
					AsyncGPUReadbackRequest item = AsyncGPUReadback.Request((Texture)(object)frame, 0, (Action<AsyncGPUReadbackRequest>)null);
					_readbackQueue.Enqueue(item);
				}
			}
			finally
			{
				((IDisposable)(AutoScope)(ref val)).Dispose();
			}
		}

		private void ProcessQueue()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			AutoScope val = ((ProfilerMarker)(ref m_processQueueMarker)).Auto();
			try
			{
				AsyncGPUReadbackRequest result;
				while (_readbackQueue.TryPeek(out result))
				{
					if (!((AsyncGPUReadbackRequest)(ref result)).done)
					{
						bool flag = false;
						foreach (AsyncGPUReadbackRequest item in _readbackQueue)
						{
							AsyncGPUReadbackRequest current = item;
							flag |= ((AsyncGPUReadbackRequest)(ref current)).done;
						}
						if (!flag)
						{
							break;
						}
						((AsyncGPUReadbackRequest)(ref result)).WaitForCompletion();
					}
					_readbackQueue.Dequeue();
					if (((AsyncGPUReadbackRequest)(ref result)).hasError)
					{
						Debug.LogError((object)"GPU readback error was detected.");
						continue;
					}
					m_pipe.PushFrameData(((AsyncGPUReadbackRequest)(ref result)).GetData<byte>(0));
					Frames++;
				}
			}
			finally
			{
				((IDisposable)(AutoScope)(ref val)).Dispose();
			}
		}

		public void Dispose()
		{
			m_pipe?.Dispose();
			m_audioData.Dispose();
			m_micAudioData.Dispose();
		}

		public void PushAudio(float[] data)
		{
			AudioDataSize = data.Length;
			for (int i = 0; i < data.Length; i++)
			{
				m_audioData.Add(ref data[i]);
			}
			AudioFrames++;
		}

		public byte[] GetAudioBlob()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			NativeSlice<byte> val = new NativeSlice<float>(NativeList<float>.op_Implicit(m_audioData)).SliceConvert<byte>();
			byte[] array = new byte[val.Length];
			val.CopyTo(array);
			return array;
		}

		public byte[] GetMicAudioBlob()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			NativeSlice<byte> val = new NativeSlice<float>(NativeList<float>.op_Implicit(m_micAudioData)).SliceConvert<byte>();
			byte[] array = new byte[val.Length];
			val.CopyTo(array);
			return array;
		}

		public string GetAudioPath()
		{
			return Pipe.GetDirectory()?.ToString() + "/audio.raw";
		}

		public string GetMicAudioPath()
		{
			return Pipe.GetDirectory()?.ToString() + "/mic.raw";
		}

		public void PushMicAudio(float[] data, int sampleRate, int channels)
		{
			//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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			float num = 1.5f;
			if (MicSampleRate.IsNone)
			{
				MicSampleRate = Optionable<int>.Some(sampleRate);
				Debug.Log((object)("Setting sample rate to: " + MicSampleRate.Value));
			}
			if (MicChannels.IsNone)
			{
				MicChannels = Optionable<int>.Some(channels);
				Debug.Log((object)("Setting channels to " + MicChannels.Value));
			}
			MicAudioDataSize = data.Length;
			for (int i = 0; i < data.Length; i++)
			{
				ref NativeList<float> micAudioData = ref m_micAudioData;
				float num2 = data[i] * num;
				micAudioData.Add(ref num2);
			}
			MicAudioFrames++;
		}

		private float MicrophoneLevelMax(float[] data)
		{
			int num = 128;
			float num2 = 0f;
			for (int i = 0; i < num; i++)
			{
				float num3 = data[i] * data[i];
				if (num2 < num3)
				{
					num2 = num3;
				}
			}
			return num2;
		}

		private float MicrophoneLevelMaxDecibels(float level)
		{
			return 20f * Mathf.Log10(Mathf.Abs(level));
		}
	}
	public class RecordingsHandler : RetrievableSingleton<RecordingsHandler>
	{
		[CompilerGenerated]
		private sealed class <CheckIfClipIsComplete>d__26 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Clip clip;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CheckIfClipIsComplete>d__26(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (!clip.local && !clip.hasBeenRecieved)
					{
						Debug.LogError((object)$"Clip chunk has not been recieved for {clip.clipID}, re-requesting...");
						RetrievableSingleton<PhotonSendVideoHandler>.Instance.ClearChunksForClip(clip.clipID);
						CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)new ReRequestClipPackage
						{
							ClipID = clip.clipID,
							VideoHandle = clip.m_recording.videoHandle
						}, (ReceiverGroup)1);
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <Encode>d__8 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Clip clip;

			public RecordingsHandler <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Encode>d__8(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				RecordingsHandler recordingsHandler = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					clip.encoded = false;
					<>2__current = recordingsHandler.m_encoder.Encode(24, FfmpegDeadline.Realtime, displayWindow: false, mic: true);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if (recordingsHandler.m_encoder.ErrorTitle != null || recordingsHandler.m_encoder.ErrorBody != null)
					{
						PeakThings.Log.LogError((object)("Ffmpeg encoding error: " + recordingsHandler.m_encoder.ErrorTitle + " - " + recordingsHandler.m_encoder.ErrorBody));
					}
					Debug.Log((object)"Encoding done!");
					recordingsHandler.m_encoder = null;
					clip.encoded = true;
					DirectoryInfo directoryInfo = new DirectoryInfo(clip.GetClipDirectory());
					Array.Empty<FileInfo>();
					if (directoryInfo.Exists)
					{
						FileInfo[] files = directoryInfo.GetFiles("*.png");
						for (int i = 0; i < files.Length; i++)
						{
							File.Delete(files[i].FullName);
						}
					}
					CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)new AddClipToShareQueuePackage
					{
						ClipID = clip.clipID,
						VideoHandle = clip.m_recording.videoHandle,
						ClipOwner = PhotonNetwork.LocalPlayer.ActorNumber,
						isReRequest = false
					}, (ReceiverGroup)1);
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ShareClipJob>d__7 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public RecordingsHandler <>4__this;

			public Clip clip;

			public bool isReRequest;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ShareClipJob>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				RecordingsHandler recordingsHandler = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = recordingsHandler.m_sendVideoHandler.SendVideoThroughPhoton(clip, isReRequest);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					Debug.Log((object)$"Clip: {clip.clipID} has sent!");
					CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)new SendClipCompletedPackage
					{
						ClipID = clip.clipID,
						VideoHandle = clip.m_recording.videoHandle
					}, (ReceiverGroup)1);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private Dictionary<VideoHandle, CameraRecording> m_recordings = new Dictionary<VideoHandle, CameraRecording>();

		private BidirectionalDictionary<Guid, VideoHandle> m_camerasCurrentRecording = new BidirectionalDictionary<Guid, VideoHandle>(10);

		private BidirectionalDictionary<int, VideoHandle> m_playersRecording = new BidirectionalDictionary<int, VideoHandle>(10);

		private ListenerHandle startRecordingHandle = ListenerHandle.Invalid;

		private ListenerHandle stopRecordingHandle = ListenerHandle.Invalid;

		private ListenerHandle clipEncodedHandle = ListenerHandle.Invalid;

		private ListenerHandle activateNextSharingJobHandle = ListenerHandle.Invalid;

		private ListenerHandle sendClipCompletedHandle = ListenerHandle.Invalid;

		private ListenerHandle reRequestClipHandle = ListenerHandle.Invalid;

		private List<VideoClipShareJob> m_sharingQueue = new List<VideoClipShareJob>();

		private VideoClipShareJob m_currentJob;

		private FfmpegEncoder m_encoder;

		private PhotonSendVideoHandler m_sendVideoHandler;

		private Dictionary<ClipID, int> m_clipRequestCount = new Dictionary<ClipID, int>();

		protected override void OnCreated()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			base.OnCreated();
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			m_clipRequestCount = new Dictionary<ClipID, int>();
			startRecordingHandle = CustomCommands<CustomCommandType>.RegisterListener<StartRecordingCommandPackage>((Action<StartRecordingCommandPackage>)OnStartRecording);
			stopRecordingHandle = CustomCommands<CustomCommandType>.RegisterListener<StopRecordingCommandPackage>((Action<StopRecordingCommandPackage>)OnStopRecording);
			clipEncodedHandle = CustomCommands<CustomCommandType>.RegisterListener<AddClipToShareQueuePackage>((Action<AddClipToShareQueuePackage>)AddClipToShareQueue);
			activateNextSharingJobHandle = CustomCommands<CustomCommandType>.RegisterListener<ActivateNextSharingJobPackage>((Action<ActivateNextSharingJobPackage>)OnActivateNextSharingJob);
			sendClipCompletedHandle = CustomCommands<CustomCommandType>.RegisterListener<SendClipCompletedPackage>((Action<SendClipCompletedPackage>)SendIsComplete);
			reRequestClipHandle = CustomCommands<CustomCommandType>.RegisterListener<ReRequestClipPackage>((Action<ReRequestClipPackage>)OnReRequestClip);
			m_sendVideoHandler = RetrievableSingleton<PhotonSendVideoHandler>.Instance;
			DirectoryInfo directoryInfo = new DirectoryInfo(GetDirectory());
			try
			{
				if (directoryInfo.Exists)
				{
					directoryInfo.Delete(recursive: true);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Failed to delete directory: " + directoryInfo.FullName + " " + ex.Message));
			}
			directoryInfo.Create();
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(directoryInfo.FullName);
			fileSystemWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.EnableRaisingEvents = true;
			fileSystemWatcher.Changed += OnFileSystemChanged;
			fileSystemWatcher.Created += OnFileSystemChanged;
			fileSystemWatcher.Deleted += OnFileSystemChanged;
			fileSystemWatcher.Renamed += OnRenamed;
			fileSystemWatcher.Error += OnFileSystemError;
			fileSystemWatcher.BeginInit();
		}

		private void OnRenamed(object sender, RenamedEventArgs e)
		{
			Debug.Log((object)$"File Watcher Event: {e.ChangeType}, old name: {e.OldName}, new name: {e.Name}, fullpath: {e.FullPath}");
		}

		private void OnFileSystemError(object sender, ErrorEventArgs e)
		{
			Debug.LogError((object)("File system error: " + e.GetException().Message));
		}

		private void OnFileSystemChanged(object sender, FileSystemEventArgs e)
		{
			Debug.Log((object)$"File Watcher Event: {e.ChangeType}, name: {e.Name}, fullpath: {e.FullPath}");
		}

		private void OnDestroy()
		{
			//IL_0001: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			CustomCommands<CustomCommandType>.UnregisterListener(startRecordingHandle);
			CustomCommands<CustomCommandType>.UnregisterListener(stopRecordingHandle);
			CustomCommands<CustomCommandType>.UnregisterListener(clipEncodedHandle);
			CustomCommands<CustomCommandType>.UnregisterListener(activateNextSharingJobHandle);
			CustomCommands<CustomCommandType>.UnregisterListener(sendClipCompletedHandle);
			CustomCommands<CustomCommandType>.UnregisterListener(reRequestClipHandle);
		}

		private void LateUpdate()
		{
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			if (RecordingPipe.CheckErrorPopup(out string title, out string body))
			{
				PeakThings.Log.LogError((object)("RecordingPipe error: " + title + " - " + body));
			}
			HashSet<int> hashSet = PhotonNetwork.PlayerList.Select((Player player) => player.ActorNumber).ToHashSet();
			foreach (CameraRecording value2 in m_recordings.Values)
			{
				int clipCount = value2.ClipCount;
				for (int i = 0; i < clipCount; i++)
				{
					Clip clip = value2.GetClip(i);
					if (!clip.local && !clip.hasBeenRecieved && clip.Valid && !hashSet.Contains(clip.ownerID))
					{
						Debug.Log((object)("Player has left, clip " + clip.clipID.ToMiniString() + " is invalid..."));
						clip.SetValid(validClip: false);
					}
				}
			}
			if (PhotonNetwork.IsMasterClient && m_sharingQueue.Count > 0 && m_currentJob == null)
			{
				m_currentJob = m_sharingQueue[0];
				m_sharingQueue.RemoveAt(0);
				CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)new ActivateNextSharingJobPackage
				{
					ClipID = m_currentJob.ClipID
				}, (ReceiverGroup)0);
			}
			VideoClipShareJob currentJob = m_currentJob;
			if (currentJob != null && currentJob.IsLocal && !currentJob.sending && PhotonNetwork.InRoom && m_recordings.TryGetValue(m_currentJob.VideoHandle, out CameraRecording value))
			{
				PeakThings.Log.LogMessage((object)$"Starting share/send video clip job: {m_currentJob.ClipID.ToShortString()} for video {value.videoHandle.id}");
				m_currentJob.sending = true;
				if (value.TryGetClip(m_currentJob.ClipID, out Clip clip2))
				{
					((MonoBehaviour)this).StartCoroutine(ShareClipJob(clip2, m_currentJob.isReRequest));
				}
				else
				{
					Debug.LogError((object)$"Error: Current share/send video clip job references clip that doesn't exist: clip {m_currentJob.ClipID.id} in video {value.videoHandle.id}");
					m_currentJob = null;
				}
			}
			if (m_encoder == null)
			{
				foreach (CameraRecording value3 in m_recordings.Values)
				{
					int clipCount2 = value3.ClipCount;
					for (int j = 0; j < clipCount2; j++)
					{
						Clip clip3 = value3.GetClip(j);
						if (clip3.local && !clip3.encoded && !clip3.isRecording && clip3.Valid)
						{
							PeakThings.Log.LogInfo((object)("Start encoding... " + clip3.clipID.ToMiniString()));
							m_encoder = new FfmpegEncoder(clip3.GetRecorder().Session);
							((MonoBehaviour)this).StartCoroutine(Encode(clip3));
						}
					}
				}
			}
			if (m_encoder != null || !Input.GetKeyDown(PeakThings.Instance.TempFileFolderKey.Value) || PeakThings.Instance.DisableFolderShortcuts.Value)
			{
				return;
			}
			Debug.Log((object)"F3 pressed");
			foreach (CameraRecording value4 in m_recordings.Values)
			{
				if (ExtractRecording(value4))
				{
					DirectoryInfo directoryInfo = new DirectoryInfo(value4.GetDirectory());
					FileInfo[] files = directoryInfo.GetFiles();
					if (files.Length != 0)
					{
						ShowExplorer(files.First().FullName);
					}
					else
					{
						ShowExplorer(directoryInfo.FullName);
					}
				}
			}
			static void ShowExplorer(string itemPath)
			{
				itemPath = itemPath.Replace("/", "\\");
				Process.Start("explorer.exe", "/select," + itemPath);
			}
		}

		public bool ExtractRecording(CameraRecording recording)
		{
			if (!recording.ReadyToExtract(out string failureReason))
			{
				Debug.LogWarning((object)("RecordingsHandler.ExtractRecording - ReadyToExtract false: " + failureReason));
				return false;
			}
			int clipCount = recording.ClipCount;
			Clip[] source = (from clip in recording.GetAllClips()
				where clip.Valid
				select clip).ToArray();
			Debug.Log((object)"All clips ready, starting stitching...");
			if (clipCount == 1)
			{
				FileInfo fileInfo = new FileInfo(Path.Combine(recording.GetClip(0).GetClipDirectory(), "output.webm"));
				if (!fileInfo.Exists)
				{
					Debug.LogError((object)("No file found to stitch: " + fileInfo.FullName));
					return false;
				}
				string text = Path.Combine(recording.GetDirectory(), "fullRecording.webm");
				Debug.Log((object)("Copying file " + fileInfo.FullName + " to: " + text));
				File.Copy(fileInfo.FullName, text, overwrite: true);
			}
			else
			{
				FFmpegStitcher.StichVideos(source.Select((Clip clip) => Path.Combine(clip.GetClipDirectory(), "output.webm")).ToArray(), recording.GetDirectory());
			}
			return true;
		}

		[IteratorStateMachine(typeof(<ShareClipJob>d__7))]
		private IEnumerator ShareClipJob(Clip clip, bool isReRequest)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ShareClipJob>d__7(0)
			{
				<>4__this = this,
				clip = clip,
				isReRequest = isReRequest
			};
		}

		[IteratorStateMachine(typeof(<Encode>d__8))]
		private IEnumerator Encode(Clip clip)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Encode>d__8(0)
			{
				<>4__this = this,
				clip = clip
			};
		}

		private void OnStartRecording(StartRecordingCommandPackage package)
		{
			Guid cameraDataGuid = package.CameraDataGuid;
			VideoHandle videoID = package.VideoID;
			int cameraOwner = package.CameraOwner;
			ClipID clipID = package.ClipID;
			if (m_camerasCurrentRecording.ContainsKey(cameraDataGuid))
			{
				Debug.LogError((object)"Camera is already recording");
				return;
			}
			Guid guid = default(Guid);
			if (m_camerasCurrentRecording.TryGetValue(videoID, ref guid))
			{
				Guid guid2 = guid;
				Debug.LogWarning((object)("Video ID is already in use by camera, stopping previous camera " + guid2));
				OnStopRecording(guid, validClip: true);
			}
			if (videoID.Equals(VideoHandle.Invalid))
			{
				Debug.LogError((object)$"Video ID is invalid, {videoID}");
				return;
			}
			if (!m_recordings.TryGetValue(videoID, out CameraRecording value))
			{
				m_recordings.Add(videoID, value = CreateNewRecording(videoID));
			}
			m_camerasCurrentRecording.Add(cameraDataGuid, videoID);
			m_playersRecording.Add(cameraOwner, videoID);
			bool local = cameraOwner == PhotonNetwork.LocalPlayer.ActorNumber;
			Clip clip = new Clip(package.ClipID, local, cameraOwner, value);
			value.AddNewClip(clip);
			Debug.Log((object)$"Start recording, camera instance id:{cameraDataGuid}, video ID: {videoID}, clip ID: {clipID}");
			if (clip.local)
			{
				if (CameraHandler.TryGetCamera(cameraDataGuid, out VideoCamera videoCamera))
				{
					videoCamera.StartRecording(clip);
				}
				else
				{
					Debug.LogError((object)$"Failed to find VideoCamera with instance id {cameraDataGuid} to start recording local clip");
				}
			}
		}

		private CameraRecording CreateNewRecording(VideoHandle entryVideoID)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Guid id = entryVideoID.id;
			Debug.Log((object)("Creating new recording: " + id));
			id = entryVideoID.id;
			CameraRecording cameraRecording = new GameObject("Recording: " + id).AddComponent<CameraRecording>();
			((Component)cameraRecording).transform.SetParent(((Component)this).transform);
			cameraRecording.SetInfo(entryVideoID);
			return cameraRecording;
		}

		private void OnStopRecording(StopRecordingCommandPackage package)
		{
			Guid cameraDataGuid = package.CameraDataGuid;
			OnStopRecording(cameraDataGuid, package.IsValidClip);
		}

		private void OnStopRecording(Guid instanceDataID, bool validClip)
		{
			if (!m_camerasCurrentRecording.ContainsKey(instanceDataID))
			{
				Debug.LogWarning((object)"Camera is not recording any video... ");
				return;
			}
			VideoHandle fromKey = m_camerasCurrentRecording.GetFromKey(instanceDataID);
			m_camerasCurrentRecording.RemoveFromKey(instanceDataID);
			Clip clip = m_recordings[fromKey].EndCurrentClip();
			clip.SetValid(validClip);
			if (m_playersRecording.Contains(fromKey))
			{
				int num = m_playersRecording.Get(fromKey);
				m_playersRecording.RemoveFromValue(fromKey);
				PeakThings.Log.LogInfo((object)$"Removed player {num} from recording");
			}
			if (clip.local)
			{
				if (CameraHandler.TryGetCamera(instanceDataID, out VideoCamera videoCamera))
				{
					videoCamera.StopRecording();
				}
				else
				{
					Debug.LogError((object)$"Failed to find VideoCamera with instance id {instanceDataID} to stop recording local clip");
				}
			}
			Debug.Log((object)$"Stop recording, camera instance id:{instanceDataID}, video ID: {fromKey.id}, clip ID: {clip.clipID.id}");
		}

		public void StartRecording(ItemInstanceData data, PhotonView playerView)
		{
			VideoInfoEntry videoInfoEntry = default(VideoInfoEntry);
			if (!data.TryGetDataEntry<VideoInfoEntry>((DataEntryKey)53, ref videoInfoEntry))
			{
				Debug.LogError((object)"No VideoInfoEntry found in instance data");
				return;
			}
			Guid guid = data.guid;
			if (videoInfoEntry.videoID.Equals(VideoHandle.Invalid))
			{
				videoInfoEntry.videoID = new VideoHandle(Guid.NewGuid());
				Debug.Log((object)$"Camera has no video ID, creating new video ID, {videoInfoEntry.videoID}");
			}
			videoInfoEntry.isRecording = true;
			videoInfoEntry.SetDirty();
			int num = -1;
			num = ((!((Object)(object)playerView != (Object)null)) ? FindFreePlayer() : playerView.OwnerActorNr);
			if (num == -1)
			{
				Debug.LogError((object)"No free player found to record camera...");
				return;
			}
			if (RetrievableSingleton<RecordingsHandler>.Instance.m_playersRecording.ContainsKey(num))
			{
				VideoHandle fromKey = RetrievableSingleton<RecordingsHandler>.Instance.m_playersRecording.GetFromKey(num);
				ItemInstanceData data2 = default(ItemInstanceData);
				if (RetrievableSingleton<RecordingsHandler>.Instance.m_camerasCurrentRecording.Contains(fromKey) && ItemInstanceDataHandler.TryGetInstanceData(RetrievableSingleton<RecordingsHandler>.Instance.m_camerasCurrentRecording.Get(fromKey), ref data2))
				{
					StopRecording(data2);
					StartRecording(data2, null);
				}
			}
			StartRecordingCommandPackage startRecordingCommandPackage = new StartRecordingCommandPackage
			{
				CameraDataGuid = guid,
				VideoID = videoInfoEntry.videoID,
				ClipID = new ClipID(Guid.NewGuid()),
				CameraOwner = num
			};
			OnStartRecording(startRecordingCommandPackage);
			CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)startRecordingCommandPackage, (ReceiverGroup)0);
		}

		private static int FindFreePlayer()
		{
			Player[] players = PhotonNetwork.PlayerList;
			int[] source = RetrievableSingleton<RecordingsHandler>.Instance.m_playersRecording.GetKeys().ToArray();
			int i;
			for (i = 0; i < players.Length; i++)
			{
				if (!source.Any((int playerID) => playerID == players[i].ActorNumber))
				{
					return players[i].ActorNumber;
				}
			}
			Debug.LogError((object)"No free player found to record camera...");
			return -1;
		}

		public void StopRecording(ItemInstanceData data)
		{
			VideoInfoEntry videoInfoEntry = default(VideoInfoEntry);
			if (!data.TryGetDataEntry<VideoInfoEntry>((DataEntryKey)53, ref videoInfoEntry))
			{
				Debug.LogError((object)"No VideoInfoEntry found in instance data");
				return;
			}
			if (!TryGetRecording(videoInfoEntry.videoID, out CameraRecording recording))
			{
				Guid id = videoInfoEntry.videoID.id;
				Debug.LogError((object)("No recording found with video ID: " + id));
				return;
			}
			if (!recording.TryGetLatestClip(out Clip clip))
			{
				Guid id2 = videoInfoEntry.videoID.id;
				Debug.LogError((object)("No clip found in recording: " + id2));
				return;
			}
			bool isValidClip = true;
			VideoRecorder recorder = clip.GetRecorder();
			if ((Object)(object)recorder == (Object)null)
			{
				Debug.LogError((object)("Failed to find recorder for clip: " + clip.clipID.ToShortString()));
				isValidClip = false;
			}
			else if (!recorder.HasRecorded)
			{
				Debug.LogError((object)"RecordingsHandler: CLIP HAS NO FRAMES!");
				isValidClip = false;
			}
			videoInfoEntry.isRecording = false;
			videoInfoEntry.SetDirty();
			Guid guid = data.guid;
			StopRecordingCommandPackage stopRecordingCommandPackage = new StopRecordingCommandPackage
			{
				CameraDataGuid = guid,
				IsValidClip = isValidClip
			};
			OnStopRecording(stopRecordingCommandPackage);
			CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)stopRecordingCommandPackage, (ReceiverGroup)0);
		}

		public static Dictionary<VideoHandle, CameraRecording> GetRecordings()
		{
			return RetrievableSingleton<RecordingsHandler>.Instance.m_recordings;
		}

		public static BidirectionalDictionary<Guid, VideoHandle> GetCamerasCurrentRecording()
		{
			return RetrievableSingleton<RecordingsHandler>.Instance.m_camerasCurrentRecording;
		}

		public static BidirectionalDictionary<int, VideoHandle> GetPlayersRecording()
		{
			return RetrievableSingleton<RecordingsHandler>.Instance.m_playersRecording;
		}

		public static string GetDirectory()
		{
			return Path.Combine(Path.GetTempPath(), "rec");
		}

		private void AddClipToShareQueue(AddClipToShareQueuePackage package)
		{
			VideoClipShareJob item = new VideoClipShareJob(package.VideoHandle, package.ClipID, package.ClipOwner, package.isReRequest);
			m_sharingQueue.Add(item);
			Debug.Log((object)$"Player {package.ClipOwner} encoded clip {package.ClipID}, added to sharing queue");
		}

		public static List<VideoClipShareJob> GetSharingQueue()
		{
			return RetrievableSingleton<RecordingsHandler>.Instance.m_sharingQueue;
		}

		public static VideoClipShareJob GetCurrentSharingJob()
		{
			return RetrievableSingleton<RecordingsHandler>.Instance.m_currentJob;
		}

		private void OnActivateNextSharingJob(ActivateNextSharingJobPackage package)
		{
			if (m_sharingQueue[0].ClipID.Equals(package.ClipID))
			{
				m_currentJob = m_sharingQueue[0];
				m_sharingQueue.RemoveAt(0);
			}
			else
			{
				Debug.LogError((object)"FATAL SHARING ERROR. Clip ID's do not match, JOBS ARE NOW WRONG VERY BAD...");
			}
		}

		private void SendIsComplete(SendClipCompletedPackage package)
		{
			PeakThings.Log.LogMessage((object)("Received clip is complete package: " + package.ClipID.ToShortString()));
			ClipID clipID = package.ClipID;
			if (TryGetRecording(package.VideoHandle, out CameraRecording recording) && recording.TryGetClip(clipID, out Clip clip))
			{
				((MonoBehaviour)this).StartCoroutine(CheckIfClipIsComplete(clip));
			}
			if (PhotonNetwork.IsMasterClient)
			{
				if (m_currentJob == null)
				{
					Debug.LogError((object)"No current job to check");
				}
				else if (m_currentJob.ClipID.Equals(package.ClipID))