Decompiled source of PeakThings v0.1.2

plugins/PeakThings/PeakThings.dll

Decompiled 9 hours 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.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[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("Debug")]
[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_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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.");
			}
			bool flag = false;
			bool flag2 = false;
			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", "1.0.0")]
	public class PeakThings : BaseUnityPlugin
	{
		public const string GUID = "evaisa.PeakThings";

		public const string ModName = "PeakThings";

		public const string Version = "1.0.0";

		private bool patchedAwake = false;

		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!" }
		};

		public bool spawnedStuffThisRun = false;

		private List<Item> itemsToRegister = new List<Item>();

		public static PeakThings Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static AssetBundle Bundle { get; set; }

		private void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "peakthings");
			((MonoBehaviour)this).StartCoroutine(LoadBundleAsync(path));
			ItemCookingHooks.Setup();
			ItemHooks.Setup();
			GameHandler.Awake += new hook_Awake(GameHandler_Awake);
			ItemDatabase.OnLoaded += new hook_OnLoaded(ItemDatabase_OnLoaded);
			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);
			BingBong.Start += new hook_Start(BingBong_Start);
			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);
		}

		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_0027: 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_0054: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_0123: 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_0153: 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_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: 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 BingBong_Start(orig_Start orig, BingBong self)
		{
			//IL_006e: 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_007e: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			spawnedStuffThisRun = true;
			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), 
			});
		}

		private IEnumerator LoadBundleAsync(string path)
		{
			AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromFileAsync(path);
			yield return bundleRequest;
			Bundle = bundleRequest.assetBundle;
			Register();
			VideoCamera.SetupCameraControllers(((Component)this).gameObject);
		}

		private void RunManager_StartRun(orig_StartRun orig, RunManager self)
		{
			//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_008f: 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)
			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"))
			{
				Log.LogInfo((object)"Spawning TVSet prefab");
				Vector3 position = default(Vector3);
				((Vector3)(ref position))..ctor(-15.29617f, 3.101736f, 116.4795f);
				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_0024: 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_0041: 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_005c: 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_0071: 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_0086: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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");
			RegisterItem(prefabs["CamcorderItem"].GetComponent<Item>());
			RegisterItem(prefabs["ArsonItem"].GetComponent<Item>());
			RegisterItem(prefabs["TapeRecording"].GetComponent<Item>());
		}

		private void RegisterItem(Item item)
		{
			itemsToRegister.Add(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();
			}
		}

		private void ItemDatabase_OnLoaded(orig_OnLoaded orig, ItemDatabase self)
		{
			foreach (Item item in itemsToRegister)
			{
				ushort key = (item.itemID = (ushort)self.itemLookup.Count);
				((DatabaseAsset<ItemDatabase, Item>)(object)self).Objects.Add(item);
				self.itemLookup.Add(key, item);
			}
			orig.Invoke(self);
		}

		public void FixPrefabReferences(GameObject prefab)
		{
			Shader shader = Shader.Find("W/Peak_Standard");
			Shader shader2 = Shader.Find("Universal Render Pipeline/Lit");
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (((Object)val.material.shader).name == "W/Peak_Standard")
				{
					val.material.shader = shader;
				}
				else
				{
					val.material.shader = shader2;
				}
			}
			Shader shader3 = Shader.Find("Shader Graphs/Decal");
			DecalProjector[] componentsInChildren2 = prefab.GetComponentsInChildren<DecalProjector>(true);
			foreach (DecalProjector val2 in componentsInChildren2)
			{
				val2.material.shader = shader3;
				Log.LogInfo((object)("Fixed decal shader for " + ((Object)val2).name + " in prefab " + ((Object)prefab).name + "."));
			}
			ParticleSystem[] componentsInChildren3 = prefab.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val3 in componentsInChildren3)
			{
				ParticleSystemRenderer component = ((Component)val3).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 val4 in componentsInChildren4)
			{
				((TMP_Text)val4).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_0087: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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.InstantiateRoomObject(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_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)
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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)
			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
	{
		private Process m_ffmpegProcess;

		private RecordingSession m_session;

		public string ErrorTitle;

		public string ErrorBody;

		public static string ExecutablePath
		{
			get
			{
				//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_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_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: 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
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Invalid comparison between Unknown and I4
				RuntimePlatform platform = Application.platform;
				RuntimePlatform val = platform;
				if ((int)val > 1)
				{
					if ((int)val == 13 || (int)val == 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;
		}

		public IEnumerator Encode(byte framerate, FfmpegDeadline deadline, bool displayWindow, bool mic)
		{
			DirectoryInfo directory = m_session.Pipe.GetDirectory();
			int audioSampleRate = AudioSettings.outputSampleRate;
			int micSampleRate = 24000;
			int micChannels = 2;
			if (m_session.MicSampleRate.IsSome)
			{
				micSampleRate = m_session.MicSampleRate.Value;
			}
			if (m_session.MicChannels.IsSome)
			{
				micChannels = m_session.MicChannels.Value;
			}
			string fullAudioPath = m_session.GetAudioPath();
			string fullMicAudioPath = m_session.GetMicAudioPath();
			SaveAudioBlobs(mic);
			yield return (object)new WaitForSecondsRealtime(0.1f);
			int frameCount = directory.GetFiles().Length;
			float duration = (float)frameCount / (float)(int)framerate;
			List<string> list = new List<string>();
			string item = directory.FullName + "/Test%04d.png";
			string outputPath = directory.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))
			{
				list.Add("-f");
				list.Add("f32le");
				list.Add("-ac");
				list.Add("2");
				list.Add("-ar");
				list.Add(audioSampleRate.ToString());
				list.Add("-thread_queue_size");
				list.Add("512");
				list.Add("-i");
				list.Add(fullAudioPath);
			}
			if (mic)
			{
				list.Add("-f");
				list.Add("f32le");
				list.Add("-ac");
				list.Add(micChannels.ToString());
				list.Add("-ar");
				list.Add(micSampleRate.ToString());
				list.Add("-thread_queue_size");
				list.Add("512");
				list.Add("-i");
				list.Add(fullMicAudioPath);
			}
			if (!string.IsNullOrEmpty(fullAudioPath))
			{
				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);
			yield return RunFfmpeg(list, displayWindow);
			float num = (float)(m_session.AudioFrames * m_session.AudioDataSize) / ((float)AudioSettings.outputSampleRate * 2f);
			Debug.Log((object)$"Encoded {directory.FullName}, {frameCount} frames, Audio Frames {m_session.AudioFrames}, Audio Data Size {m_session.AudioDataSize}, Audio Duration {num:F}s, Video Duration {duration:F}s");
			if (!File.Exists(outputPath))
			{
				if (ErrorTitle == null)
				{
					ErrorTitle = "Encode FAIL, Video path not found";
					ErrorBody = outputPath;
				}
				Debug.LogError((object)("Encode FAIL, Video path not found" + outputPath));
			}
		}

		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();
			}
		}

		private IEnumerator RunFfmpeg(List<string> arguments, bool displayWindow)
		{
			Debug.Log((object)("Running FFmpeg encode... " + string.Join(" ", arguments)));
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.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
			{
				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)");
				ErrorTitle = "Failed to start ffmpeg to encode video";
				if (ex is Win32Exception ex2 && ex2.ToString().Contains("Access is denied"))
				{
					ErrorTitle += " (Access is denied)";
				}
				ErrorBody = ex.ToString();
				yield break;
			}
			if (m_ffmpegProcess == null)
			{
				Debug.LogError((object)"Process.Start returned null (as a result, we probably failed to encode)");
				ErrorTitle = "Failed to start ffmpeg to encode video";
				ErrorBody = "Process.Start returned null";
				yield break;
			}
			Task<string> outputTask = m_ffmpegProcess.StandardError.ReadToEndAsync();
			while (!m_ffmpegProcess.HasExited)
			{
				yield return null;
			}
			if (!outputTask.IsCompleted)
			{
				yield return (object)new WaitUntil((Func<bool>)(() => outputTask.IsCompleted));
			}
			string result = outputTask.Result;
			stopwatch.Stop();
			Debug.Log((object)$"FFmpeg took {stopwatch.Elapsed.TotalSeconds:F3}s to encode the video.");
			if (!string.IsNullOrWhiteSpace(result))
			{
				Debug.Log((object)$"Encoder FFmpeg stderr (exit code {m_ffmpegProcess.ExitCode}) {result}");
			}
			m_ffmpegProcess.Dispose();
		}
	}
	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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_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)
			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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0035: 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_003f: 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_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_0058: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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)
			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_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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_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_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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			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_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			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_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0065: 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)
			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>
	{
		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_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)
			//IL_0043: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			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_0002: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_003e: 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()
		{
			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((KeyCode)284))
			{
				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;
		}

		private IEnumerator ShareClipJob(Clip clip, bool isReRequest)
		{
			yield return m_sendVideoHandler.SendVideoThroughPhoton(clip, isReRequest);
			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);
		}

		private IEnumerator Encode(Clip clip)
		{
			clip.encoded = false;
			yield return m_encoder.Encode(24, FfmpegDeadline.Realtime, displayWindow: false, mic: true);
			if (m_encoder.ErrorTitle != null || m_encoder.ErrorBody != null)
			{
				PeakThings.Log.LogError((object)("Ffmpeg encoding error: " + m_encoder.ErrorTitle + " - " + m_encoder.ErrorBody));
			}
			Debug.Log((object)"Encoding done!");
			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);
		}

		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_0043: 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))
				{
					m_currentJob = null;
					PeakThings.Log.LogMessage((object)"Clip is complete, removing from current job");
				}
				else
				{
					Debug.LogError((object)"FATAL SHARING ERROR. Clip ID's do not match, JOBS ARE NOW WRONG VERY BAD...");
				}
			}
		}

		private void OnReRequestClip(ReRequestClipPackage obj)
		{
			Debug.Log((object)("Received re-request clip package: " + obj.ClipID.ToShortString()));
			if (!TryGetRecording(obj.VideoHandle, out CameraRecording recording) || !recording.TryGetClip(obj.ClipID, out Clip clip))
			{
				return;
			}
			int valueOrDefault = m_clipRequestCount.GetValueOrDefault(obj.ClipID, 0);
			if (clip.local && valueOrDefault < 4)
			{
				if (!m_clipRequestCount.ContainsKey(obj.ClipID))
				{
					m_clipRequestCount.Add(obj.ClipID, 0);
				}
				m_clipRequestCount[obj.ClipID] = valueOrDefault + 1;
				CustomCommands<CustomCommandType>.SendPackage((CustomCommandPackage<CustomCommandType>)new AddClipToShareQueuePackage
				{
					ClipID = clip.clipID,
					VideoHandle = clip.m_recording.videoHandle,
					ClipOwner = PhotonNetwork.LocalPlayer.ActorNumber,
					isReRequest = true
				}, (ReceiverGroup)1);
			}
		}

		private IEnumerator CheckIfClipIsComplete(Clip clip)
		{
			yield return (object)new WaitForSeconds(2f);
			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);
			}
		}

		public static void RecievedClip(VideoHandle chunkVideoID, ClipID chunkClipID)
		{
			if (RetrievableSingleton<RecordingsHandler>.Instance.m_recordings.TryGetValue(chunkVideoID, out CameraRecording value))
			{
				if (value.TryGetClip(chunkClipID, out Clip clip))
				{
					clip.hasBeenRecieved = true;
				}
				else
				{
					Debug.LogError((object)$"Error: Received clip data for clip that we don't have! Ignoring clip data. video={chunkVideoID} clip={chunkClipID}");
				}
			}
			else
			{
				Debug.LogError((object)$"Error: Received clip data for video that we don't have! Ignoring clip data. video={chunkVideoID} clip={chunkClipID}");
			}
		}

		public static bool TryGetRecording(VideoHandle tVideoID, out CameraRecording recording)
		{
			return RetrievableSingleton<RecordingsHandler>.Instance.m_recordings.TryGetValue(tVideoID, out recording);
		}

		public static bool GetAllRecordings(out Dictionary<VideoHandle, CameraRecording> recordings)
		{
			recordings = RetrievableSingleton<RecordingsHandler>.Instance.m_recordings;
			return recordings.Count > 0;
		}

		public static bool TryGetRecordingPath(VideoHandle videoHandle, out string path)
		{
			if (TryGetRecording(videoHandle, out CameraRecording recording))
			{
				path = Path.Combine(recording.GetDirectory(), "fullRecording.webm");
				return true;
			}
			path = null;
			return false;
		}

		public void ClearRecordings()
		{
			PeakThings.Log.LogInfo((object)"Clearing all recordings... SURELY.");
			foreach (KeyValuePair<VideoHandle, CameraRecording> recording in m_recordings)
			{
				ClearRecording(recording.Key);
			}
			m_recordings.Clear();
			m_camerasCurrentRecording.Clear();
			m_playersRecording.Clear();
			m_sharingQueue.Clear();
			m_currentJob = null;
			m_clipRequestCount.Clear();
			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();
			Debug.Log((object)"All recordings cleared.");
		}

		public void ClearRecording(VideoHandle videoHandle)
		{
			if (m_recordings.TryGetValue(videoHandle, out CameraRecording value))
			{
				m_recordings.Remove(videoHandle);
				m_camerasCurrentRecording.RemoveFromValue(videoHandle);
				m_playersRecording.RemoveFromValue(videoHandle);
				Object.Destroy((Object)(object)((Component)value).gameObject);
			}
			else
			{
				Guid id = videoHandle.id;
				Debug.LogWarning((object)("No recording found with video handle: " + id));
			}
		}

		protected override void OnRemoved()
		{
			base.OnRemoved();
			foreach (KeyValuePair<VideoHandle, CameraRecording> recording in m_recordings)
			{
				int clipCount = recording.Value.ClipCount;
				for (int i = 0; i < clipCount; i++)
				{
					VideoRecorder recorder = recording.Value.GetClip(i).GetRecorder();
					if ((Object)(object)recorder != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)recorder).gameObject);
					}
				}
			}
		}
	}
	public class VideoChunk
	{
		private byte[][] m_chunks;

		public ClipID ClipID { get; }

		public VideoHandle VideoID { get; }

		public byte[] ChunkData { get; private set; }

		public bool Completed { get; private set; }

		private bool IsReadyForMakeVideo
		{
			get
			{
				byte[][] chunks = m_chunks;
				for (int i = 0; i < chunks.Length; i++)
				{
					if (chunks[i] == null)
					{
						return false;
					}
				}
				return true;
			}
		}

		public VideoChunk(ushort chunkCount, ClipID clipID, VideoHandle videoID)
		{
			VideoID = videoID;
			ClipID = clipID;
			m_chunks = new byte[chunkCount][];
			PeakThings.Log.LogInfo((object)$"Received first chunk: clipID: {ClipID.id} Video ID: {VideoID} Expecting Number Of Chunks: {chunkCount}");
		}

		public void AddChunk(byte[] chunkData, ushort index)
		{
			PeakThings.Log.LogInfo((object)$"Adding Video ChunkIndex: {index} Data Length: {chunkData.Length} Video ID: {VideoID} Clip ID: {ClipID}");
			m_chunks[index] = chunkData;
			if (IsReadyForMakeVideo)
			{
				MakeVideo();
				Completed = true;
			}
		}

		private void MakeVideo()
		{
			int num = 0;
			byte[][] chunks = m_chunks;
			byte[][] array = chunks;
			foreach (byte[] array2 in array)
			{
				num += array2.Length;
			}
			PeakThings.Log.LogInfo((object)("Chunks Complete: TotalBytes " + num));
			int num2 = 0;
			byte[] array3 = new byte[num];
			chunks = m_chunks;
			byte[][] array4 = chunks;
			foreach (byte[] array5 in array4)
			{
				Array.Copy(array5, 0, array3, num2, array5.Length);
				num2 += array5.Length;
			}
			ChunkData = array3;
		}
	}
	public class VideoClipShareJob
	{
		public bool isReRequest;

		public VideoHandle VideoHandle { get; private set; }

		public ClipID ClipID { get; private set; }

		public int ClipOwner { get; private set; }

		public bool IsLocal { get; private set; }

		public bool sending { get; set; }

		public VideoClipShareJob(VideoHandle videoHandle, ClipID clipID, int clipOwner, bool isReRequest)
		{
			this.isReRequest = isReRequest;
			VideoHandle = videoHandle;
			ClipID = clipID;
			ClipOwner = clipOwner;
			IsLocal = PhotonNetwork.LocalPlayer.ActorNumber == clipOwner;
		}
	}
	public struct VideoHandle : IComparable<VideoHandle>, IEquatable<VideoHandle>
	{
		public Guid id;

		public static VideoHandle Invalid => new VideoHandle(Guid.Empty);

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

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

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

		public override bool Equals(object obj)
		{
			if (obj is VideoHandle other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return id.GetHashCode();
		}

		public override string ToString()
		{
			return id.ToString();
		}
	}
	public class VideoInfoEntry : DataEntryValue
	{
		private bool m_dirty;

		private bool m_forceDirty;

		public VideoHandle videoID;

		public float timeLeft;

		public float maxTime;

		public bool isRecording { get; set; }

		public bool isFlipped { get; set; }

		public float timeRecorded => maxTime - timeLeft;

		public bool StartedRecording => videoID.id != default(Guid);

		public override void SerializeValue(BinarySerializer binarySerializer)
		{
			binarySerializer.WriteFloat(timeLeft);
			binarySerializer.WriteFloat(maxTime);
			binarySerializer.WriteBool(isRecording);
			binarySerializer.WriteBool(isFlipped);
			binarySerializer.WriteGuid(videoID.id);
		}

		public void SetDirty()
		{
			m_dirty = true;
		}

		public void SetForceDirty()
		{
			m_forceDirty = true;
		}

		public bool IsDirty()
		{
			return m_dirty;
		}

		public bool IsForceDirty()
		{
			return m_forceDirty;
		}

		public void ClearDirty()
		{
			m_dirty = false;
		}

		public void ClearForceDirty()
		{
			m_forceDirty = false;
		}

		public override void DeserializeValue(BinaryDeserializer binaryDeserializer)
		{
			timeLeft = binaryDeserializer.ReadFloat();
			maxTime = binaryDeserializer.ReadFloat();
			isRecording = binaryDeserializer.ReadBool();
			isFlipped = binaryDeserializer.ReadBool();
			videoID = new VideoHandle(binaryDeserializer.ReadGuid());
		}

		public string GetString()
		{
			int num = Mathf.CeilToInt(GetPercentage() * 100f);
			string arg = "Film left";
			return $"{num} {arg}";
		}

		public float GetPercentage()
		{
			return math.saturate(timeLeft / maxTime);
		}
	}
	public class VideoRecorder : MonoBehaviour
	{
		public enum VideoInputMode
		{
			Camera,
			RenderTexture
		}

		public string OutputPath;

		public bool m_record;

		public bool m_recordMicrophone;

		public VideoInputMode m_inputMode;

		public Camera m_camera;

		public RenderTexture m_renderTexture;

		public RecorderAudioListener m_audioListener;

		public uint m_width = 480u;

		public uint m_height = 480u;

		public byte frameRate = 10;

		private RenderTexture m_cameraTexture;

		private RecordingSession m_session;

		private float m_timer;

		private bool m_recordLastFrame;

		public RecordingSession Session => m_session;

		public bool HasRecorded
		{
			get
			{
				if (m_session != null && m_session.Frames > 0)
				{
					return true;
				}
				return false;
			}
		}

		public void RecordFrame()
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			if (string.IsNullOrEmpty(OutputPath))
			{
				Debug.LogError((object)"Output path is not set");
				return;
			}
			if (m_session == null)
			{
				m_session = new RecordingSession(m_width, m_height, OutputPath);
			}
			if (m_inputMode == VideoInputMode.Camera)
			{
				if ((Object)(object)m_cameraTexture == (Object)null)
				{
					m_cameraTexture = new RenderTexture((int)m_width, (int)m_height, 24, (RenderTextureFormat)7, 0);
				}
				RenderTexture targetTexture = m_camera.targetTexture;
				m_camera.targetTexture = m_cameraTexture;
				m_camera.Render();
				m_camera.targetTexture = targetTexture;
				m_session.PushFrame(m_cameraTexture);
			}
			else
			{
				m_session.PushFrame(m_renderTexture);
			}
		}

		private void LateUpdate()
		{
			float num = 1f / (float)(int)frameRate;
			if (m_record != m_recordLastFrame && m_record)
			{
				m_timer = num;
			}
			m_recordLastFrame = m_record;
			_ = m_record;
			m_timer += Time.unscaledDeltaTime;
			if (m_session != null && m_timer < num)
			{
				m_session.PushFrame(null);
			}
			while (m_timer >= num)
			{
				m_timer -= num;
				if (!m_record)
				{
					continue;
				}
				if (m_inputMode == VideoInputMode.Camera)
				{
					if ((Object)(object)m_camera != (Object)null)
					{
						RecordFrame();
					}
				}
				else if ((Object)(object)m_renderTexture != (Object)null)
				{
					RecordFrame();
				}
				else
				{
					m_record = false;
					Debug.LogWarning((object)"Render texture is null, stopping recording");
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)m_cameraTexture != (Object)null)
			{
				m_cameraTexture.Release();
			}
			m_session?.Dispose();
		}

		public void AudioRead(float[] data)
		{
			if (m_record)
			{
				m_session?.PushAudio(data);
			}
		}

		public void PushMicData(float[] buffer, int sampleRate, int channels)
		{
			if (m_record && m_recordMicrophone)
			{
				m_session?.PushMicAudio(buffer, sampleRate, channels);
			}
		}
	}
}
namespace Evaisa.PeakThings.Recorder.ImageEncoding
{
	[BurstCompile]
	public struct EncodePngJob : IJob
	{
		[ReadOnly]
		[DeallocateOnJobCompletion]
		public NativeArray<byte> Input;

		public uint Width;

		public uint Height;

		public NativeList<byte> Output;

		public unsafe void Execute()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			NativeArray<byte> val = ImageConversion.EncodeNativeArrayToPNG<byte>(Input, (GraphicsFormat)4, Width, Height, 0u);
			Output.Resize(val.Length, (NativeArrayOptions)0);
			void* unsafeBufferPointerWithoutChecks = NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks<byte>(val);
			UnsafeUtility.MemCpy(NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks<byte>(NativeList<byte>.op_Implicit(Output)), unsafeBufferPointerWithoutChecks, (long)(val.Length * UnsafeUtility.SizeOf<byte>()));
			val.Dispose();
		}
	}
}
namespace Evaisa.PeakThings.Recorder.CommandPackages
{
	public class ActivateNextSharingJobPackage : CustomCommandPackage<CustomCommandType>
	{
		public ClipID ClipID;

		protected override void SerializeData(BinarySerializer binarySerializer)
		{
			binarySerializer.WriteGuid(ClipID.id);
		}

		public override void DeserializeData(BinaryDeserializer binaryDeserializer)
		{
			ClipID = new ClipID(binaryDeserializer.ReadGuid());
		}

		public override CustomCommandType GetCommandType()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return (CustomCommandType)2456;
		}

		public override SendOptions GetSendOptions()
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			return SendOptions.SendReliable;
		}
	}
	public class AddClipToShareQueuePackage : CustomCommandPackage<CustomCommandType>
	{
		public VideoHandle VideoHandle;

		public ClipID ClipID;

		public int ClipOwner;

		public bool isReRequest;

		protected override void SerializeData(BinarySerializer binarySerializer)
		{
			binarySerializer.WriteInt(ClipOwner);
			binarySerializer.WriteGuid(VideoHandle.id);
			binarySerializer.WriteGuid(ClipID.id);
			binarySerializer.WriteBool(isReRequest);
		}

		public override void DeserializeData(BinaryDeserializer binaryDeserializer)
		{
			ClipOwner = binaryDeserializer.ReadInt();
			VideoHandle = new VideoHandle(binaryDeserializer.ReadGuid());
			ClipID = new ClipID(binaryDeserializer.ReadGuid());
			isReRequest = binaryDeserializer.ReadBool();
		}

		public override CustomCommandType GetCommandType()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return (CustomCommandType)2455;
		}

		public override SendOptions GetSendOptions()
		{
			//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_0009: Unknown result type (might be due to invalid IL or missing references)
			return SendOptions.SendReliable;
		}
	}
	public class PhotonSendVideoHandler : RetrievableSingleton<PhotonSendVideoHandler>
	{
		private readonly string VIDEO_EXTENSION = ".webm";

		private const float TIMER_PER_PACKAGE = 0.5f;

		private const int BYTES_PER_CHUNK = 30000;

		private string PATH_TO_VIDEO;

		private ListenerHandle m_sendChunkListenHandle;

		private Dictionary<ClipID, VideoChunk> m_VideoChunkDic = new Dictionary<ClipID, VideoChunk>();

		protected override void OnCreated()
		{
			//IL_0027: 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)
			base.OnCreated();
			PATH_TO_VIDEO = RecordingsHandler.GetDirectory();
			InitSendVideoHandler();
			m_sendChunkListenHandle = CustomCommands<CustomCommandType>.RegisterListener<SendVideoChunkPackage>((Action<SendVideoChunkPackage>)RecieveClipChunk);
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}

		private void OnDestroy()
		{
			//IL_0002: Unk