The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of PeakThings v0.1.2
plugins/PeakThings/PeakThings.dll
Decompiled 9 hours ago
The result has been truncated due to the large size, download it to view full contents!
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