Decompiled source of ReFract Reloaded v1.0.0

Renderer/BepInEx/plugins/ReFract.Unity/ReFract_Unity.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using InterprocessLib;
using Microsoft.CodeAnalysis;
using ReFract.Shared;
using Renderite.Shared;
using Renderite.Unity;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Noble")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ee3e5f831ac7344dd0428b7fb2892aa037ae0923")]
[assembly: AssemblyProduct("Re:Fract // Reloaded (for Unity)")]
[assembly: AssemblyTitle("ReFract_Unity")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/noblereign/ReFract-ReLoaded")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 ReFract.Shared
{
	public enum ReFractCommandValueType : byte
	{
		Int,
		Float,
		Bool,
		Color,
		Vector2,
		Vector4,
		String
	}
	public struct ReFractColor
	{
		public float r;

		public float g;

		public float b;

		public float a;

		public override string ToString()
		{
			return $"({r}, {g}, {b}, {a})";
		}
	}
	public struct ReFractVector2
	{
		public float x;

		public float y;

		public override string ToString()
		{
			return $"({x}, {y})";
		}
	}
	public struct ReFractVector4
	{
		public float x;

		public float y;

		public float z;

		public float w;

		public override string ToString()
		{
			return $"({x}, {y}, {z}, {w})";
		}
	}
	public class ReFractCommand : RendererCommand
	{
		public int RenderTextureId;

		public bool IsRemoveAlphaCommand;

		public string CameraName = "";

		public string ComponentName = "";

		public string ParameterName = "";

		public ReFractCommandValueType ValueType;

		public int IntValue;

		public float FloatValue;

		public bool BoolValue;

		public ReFractColor ColorValue;

		public ReFractVector2 Vector2Value;

		public ReFractVector4 Vector4Value;

		public string StringValue = "";

		public override void Pack(ref MemoryPacker packer)
		{
			((MemoryPacker)(ref packer)).Write<int>(RenderTextureId);
			((MemoryPacker)(ref packer)).Write<bool>(IsRemoveAlphaCommand);
			((MemoryPacker)(ref packer)).Write(CameraName);
			((MemoryPacker)(ref packer)).Write(ComponentName);
			((MemoryPacker)(ref packer)).Write(ParameterName);
			((MemoryPacker)(ref packer)).Write<byte>((byte)ValueType);
			switch (ValueType)
			{
			case ReFractCommandValueType.Int:
				((MemoryPacker)(ref packer)).Write<int>(IntValue);
				break;
			case ReFractCommandValueType.Float:
				((MemoryPacker)(ref packer)).Write<float>(FloatValue);
				break;
			case ReFractCommandValueType.Bool:
				((MemoryPacker)(ref packer)).Write<bool>(BoolValue);
				break;
			case ReFractCommandValueType.Color:
				((MemoryPacker)(ref packer)).Write<float>(ColorValue.r);
				((MemoryPacker)(ref packer)).Write<float>(ColorValue.g);
				((MemoryPacker)(ref packer)).Write<float>(ColorValue.b);
				((MemoryPacker)(ref packer)).Write<float>(ColorValue.a);
				break;
			case ReFractCommandValueType.Vector2:
				((MemoryPacker)(ref packer)).Write<float>(Vector2Value.x);
				((MemoryPacker)(ref packer)).Write<float>(Vector2Value.y);
				break;
			case ReFractCommandValueType.Vector4:
				((MemoryPacker)(ref packer)).Write<float>(Vector4Value.x);
				((MemoryPacker)(ref packer)).Write<float>(Vector4Value.y);
				((MemoryPacker)(ref packer)).Write<float>(Vector4Value.z);
				((MemoryPacker)(ref packer)).Write<float>(Vector4Value.w);
				break;
			case ReFractCommandValueType.String:
				((MemoryPacker)(ref packer)).Write(StringValue);
				break;
			}
		}

		public override void Unpack(ref MemoryUnpacker unpacker)
		{
			((MemoryUnpacker)(ref unpacker)).Read<int>(ref RenderTextureId);
			((MemoryUnpacker)(ref unpacker)).Read<bool>(ref IsRemoveAlphaCommand);
			((MemoryUnpacker)(ref unpacker)).Read(ref CameraName);
			((MemoryUnpacker)(ref unpacker)).Read(ref ComponentName);
			((MemoryUnpacker)(ref unpacker)).Read(ref ParameterName);
			((MemoryUnpacker)(ref unpacker)).Read<ReFractCommandValueType>(ref ValueType);
			switch (ValueType)
			{
			case ReFractCommandValueType.Int:
				((MemoryUnpacker)(ref unpacker)).Read<int>(ref IntValue);
				break;
			case ReFractCommandValueType.Float:
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref FloatValue);
				break;
			case ReFractCommandValueType.Bool:
				((MemoryUnpacker)(ref unpacker)).Read<bool>(ref BoolValue);
				break;
			case ReFractCommandValueType.Color:
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref ColorValue.r);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref ColorValue.g);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref ColorValue.b);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref ColorValue.a);
				break;
			case ReFractCommandValueType.Vector2:
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref Vector2Value.x);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref Vector2Value.y);
				break;
			case ReFractCommandValueType.Vector4:
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref Vector4Value.x);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref Vector4Value.y);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref Vector4Value.z);
				((MemoryUnpacker)(ref unpacker)).Read<float>(ref Vector4Value.w);
				break;
			case ReFractCommandValueType.String:
				((MemoryUnpacker)(ref unpacker)).Read(ref StringValue);
				break;
			}
		}
	}
	internal class ReFractConfig
	{
		public readonly ConfigEntry<bool> debugLogging;

		public readonly ConfigEntry<bool> forceRemoveAlpha;

		public ReFractConfig(ConfigFile cfg)
		{
			cfg.SaveOnConfigSet = false;
			debugLogging = cfg.Bind<bool>("General", "Debug logging", false, "Whether or not to print debug logging. This can make your log files grow incredibly quickly, only enable it if you really need it");
			forceRemoveAlpha = cfg.Bind<bool>("General", "Always reset alpha channel", false, "By default, Re:Fract embeds the depth data of photos in the alpha channel. If you're using a camera without the option to disable that behavior, you can force it to happen here.");
			ClearOrphanedEntries(cfg);
			cfg.Save();
			cfg.SaveOnConfigSet = true;
		}

		private static void ClearOrphanedEntries(ConfigFile cfg)
		{
			((Dictionary<ConfigDefinition, string>)AccessTools.Property(typeof(ConfigFile), "OrphanedEntries").GetValue(cfg)).Clear();
		}
	}
}
namespace ReFract.Unity
{
	public static class Introspection
	{
		public delegate void RefAction<T1, T2>(ref T1 obj, T2 value);

		public static Dictionary<Type, Dictionary<string, RefAction<object, object>>> _cachedSetters = new Dictionary<Type, Dictionary<string, RefAction<object, object>>>();

		public static Dictionary<Type, Dictionary<string, Action<object, object>>> _cachedPropSetters = new Dictionary<Type, Dictionary<string, Action<object, object>>>();

		private static void DoDebugLog(string input)
		{
			if (Plugin.BoundConfig.debugLogging.Value)
			{
				Debug.Log((object)input);
			}
		}

		public static RefAction<object, object>? GetFieldSetter(Type obj, string fieldName, Func<Type, FieldInfo, ILGenerator, bool>? ilOverride = null)
		{
			try
			{
				return _cachedSetters[obj][fieldName];
			}
			catch
			{
				if (obj == null || fieldName == null || fieldName.Length == 0)
				{
					return null;
				}
				DoDebugLog("Introspection : Getting field");
				FieldInfo field = obj.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				DoDebugLog("Introspection : Field is " + ((field == null) ? "null" : "not null"));
				if (field == null)
				{
					return null;
				}
				DoDebugLog("Introspection : Field is " + field.Name);
				RefAction<object, object> dynamicMethod = GetDynamicMethod(obj, field, ilOverride);
				DoDebugLog("Introspection : Delegate is " + ((dynamicMethod == null) ? "null" : ("not null & " + dynamicMethod.GetType().ToString())));
				if (dynamicMethod == null)
				{
					return null;
				}
				if (!_cachedSetters.ContainsKey(obj))
				{
					_cachedSetters.Add(obj, new Dictionary<string, RefAction<object, object>>());
				}
				_cachedSetters[obj].Add(fieldName, dynamicMethod);
				DoDebugLog("Introspection : Added delegate to dictionary at " + obj.ToString() + "." + fieldName);
				return dynamicMethod;
			}
		}

		public static Action<object, object>? GetPropSetter(Type obj, string propName)
		{
			try
			{
				return _cachedPropSetters[obj][propName];
			}
			catch
			{
				if (obj == null || propName == null || propName.Length == 0)
				{
					return null;
				}
				DoDebugLog("Introspection : Getting property of " + obj.ToString() + " with name " + propName);
				PropertyInfo property = obj.GetProperty(propName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				DoDebugLog("Introspection : Property is " + ((property == null) ? "null" : "not null"));
				if (property == null)
				{
					return null;
				}
				DoDebugLog("Introspection : Property is " + property.Name);
				Action<object, object> dynamicPropMethod = GetDynamicPropMethod(obj, property);
				DoDebugLog("Introspection : Delegate is " + ((dynamicPropMethod == null) ? "null" : ("not null & " + dynamicPropMethod.GetType().ToString())));
				if (dynamicPropMethod == null)
				{
					return null;
				}
				if (!_cachedPropSetters.ContainsKey(obj))
				{
					_cachedPropSetters.Add(obj, new Dictionary<string, Action<object, object>>());
				}
				_cachedPropSetters[obj].Add(propName, dynamicPropMethod);
				DoDebugLog("Introspection : Added delegate to dictionary at " + obj.ToString() + "." + propName);
				return dynamicPropMethod;
			}
		}

		public static RefAction<object, object> GetDynamicMethod(Type obj, FieldInfo field, Func<Type, FieldInfo, ILGenerator, bool>? ilOverride = null)
		{
			DynamicMethod dynamicMethod = new DynamicMethod("", null, new Type[2]
			{
				typeof(object).MakeByRefType(),
				typeof(object)
			}, restrictedSkipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator(256);
			Label label = iLGenerator.DefineLabel();
			iLGenerator.DefineLabel();
			Label label2 = iLGenerator.DefineLabel();
			Label label3 = iLGenerator.DefineLabel();
			if (ilOverride == null || !ilOverride(obj, field, iLGenerator))
			{
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetType"));
				iLGenerator.Emit(OpCodes.Ldtoken, typeof(int));
				iLGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
				iLGenerator.Emit(OpCodes.Ceq);
				iLGenerator.Emit(OpCodes.Brfalse, label2);
				iLGenerator.Emit(OpCodes.Ldtoken, field.FieldType);
				iLGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
				iLGenerator.Emit(OpCodes.Call, typeof(Type).GetProperty("IsEnum").GetGetMethod());
				iLGenerator.Emit(OpCodes.Brtrue, label3);
				iLGenerator.MarkLabel(label2);
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetType"));
				iLGenerator.Emit(OpCodes.Ldtoken, field.FieldType);
				iLGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
				iLGenerator.Emit(OpCodes.Ceq);
				iLGenerator.Emit(OpCodes.Brfalse, label);
				iLGenerator.MarkLabel(label3);
				iLGenerator.Emit(OpCodes.Ldarg_0);
				iLGenerator.Emit(OpCodes.Ldind_Ref);
				iLGenerator.Emit(OpCodes.Castclass, obj);
				iLGenerator.Emit(OpCodes.Ldarg_1);
				iLGenerator.Emit(OpCodes.Unbox_Any, field.FieldType);
				iLGenerator.Emit(OpCodes.Stfld, field);
				iLGenerator.Emit(OpCodes.Ret);
				iLGenerator.MarkLabel(label);
				iLGenerator.Emit(OpCodes.Ldstr, $"[Re:Fract] Introspection : Wrong type for field \"{field.Name}\" which takes \"{field.FieldType}\"");
				iLGenerator.Emit(OpCodes.Call, typeof(Debug).GetMethod("LogWarning", new Type[1] { typeof(string) }));
				iLGenerator.Emit(OpCodes.Ret);
				DoDebugLog("Introspection : Generated dynamic method with default IL");
			}
			DoDebugLog("Introspection : Creation of DynamicMethod was successful for " + obj.ToString() + "." + field.Name);
			return (RefAction<object, object>)dynamicMethod.CreateDelegate(typeof(RefAction<, >).MakeGenericType(typeof(object), typeof(object)));
		}

		public static Action<object, object>? GetDynamicPropMethod(Type obj, PropertyInfo prop)
		{
			if (obj == null || prop == null || !prop.CanWrite)
			{
				return null;
			}
			MethodInfo setMethod = prop.GetSetMethod(nonPublic: true);
			if (setMethod == null)
			{
				return null;
			}
			DynamicMethod dynamicMethod = new DynamicMethod("", null, new Type[2]
			{
				typeof(object),
				typeof(object)
			}, restrictedSkipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator(256);
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Castclass, obj);
			iLGenerator.Emit(OpCodes.Ldarg_1);
			iLGenerator.Emit(OpCodes.Unbox_Any, prop.PropertyType);
			iLGenerator.Emit(OpCodes.Call, setMethod);
			iLGenerator.Emit(OpCodes.Ret);
			DoDebugLog("Introspection : Created delegate for property " + prop.Name);
			return (Action<object, object>)dynamicMethod.CreateDelegate(typeof(Action<object, object>));
		}
	}
	public class ReFractVolumeTracker : MonoBehaviour
	{
		public GameObject VolumeObject;

		private void OnDestroy()
		{
			if ((Object)(object)VolumeObject != (Object)null)
			{
				Object.Destroy((Object)(object)VolumeObject);
				return;
			}
			Transform val = ((Component)this).transform.Find("ReFract_Volume");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}
	}
	[BepInPlugin("dog.glacier.ReFractUnity", "Re:Fract // Reloaded (for Unity)", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(CameraRenderer), "Render")]
		public static class CameraRenderer_Patch
		{
			private static FieldInfo _cameraField;

			private static FieldInfo _camera360Field;

			private static Camera FindSourceCamera(CameraRenderTask task)
			{
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Invalid comparison between Unknown and I4
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c2: Invalid comparison between Unknown and I4
				//IL_0131: Unknown result type (might be due to invalid IL or missing references)
				//IL_0136: 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_014a: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(task.position.x, task.position.y, task.position.z);
				Quaternion val2 = default(Quaternion);
				((Quaternion)(ref val2))..ctor(task.rotation.x, task.rotation.y, task.rotation.z, task.rotation.w);
				Camera result = null;
				float num = float.MaxValue;
				foreach (List<Camera> value in _cameraCache.Values)
				{
					if (value == null)
					{
						continue;
					}
					foreach (Camera item in value)
					{
						if ((Object)(object)item == (Object)null)
						{
							continue;
						}
						if (item.orthographic)
						{
							if ((int)task.parameters.projection != 1 || Mathf.Abs(item.orthographicSize - task.parameters.orthographicSize) > 0.01f)
							{
								continue;
							}
						}
						else if ((int)task.parameters.projection == 1 || (task.parameters.fov < 180f && Mathf.Abs(item.fieldOfView - task.parameters.fov) > 5f))
						{
							continue;
						}
						float num2 = Vector3.Distance(((Component)item).transform.position, val);
						float num3 = Quaternion.Angle(((Component)item).transform.rotation, val2);
						if (num2 < 2f && num3 < 15f && num2 < num)
						{
							num = num2;
							result = item;
						}
					}
				}
				return result;
			}

			private static Camera GetCaptureCamera(CameraRenderTask task)
			{
				if (task.parameters.fov >= 180f)
				{
					if (_camera360Field == null)
					{
						_camera360Field = AccessTools.Field(typeof(CameraRenderer), "camera360");
					}
					object value = _camera360Field.GetValue(null);
					if (value == null)
					{
						return null;
					}
					object? obj = AccessTools.Property(value.GetType(), "Camera")?.GetValue(value);
					return (Camera)((obj is Camera) ? obj : null);
				}
				if (_cameraField == null)
				{
					_cameraField = AccessTools.Field(typeof(CameraRenderer), "camera");
				}
				object? value2 = _cameraField.GetValue(null);
				return (Camera)((value2 is Camera) ? value2 : null);
			}

			[HarmonyPrefix]
			public static void Prefix(CameraRenderTask task, out Camera __state)
			{
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0178: 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_018f: Unknown result type (might be due to invalid IL or missing references)
				__state = null;
				Camera captureCamera = GetCaptureCamera(task);
				if ((Object)(object)captureCamera == (Object)null)
				{
					return;
				}
				Camera val = (__state = FindSourceCamera(task));
				PostProcessVolume component = ((Component)captureCamera).gameObject.GetComponent<PostProcessVolume>();
				Transform val2 = ((Component)captureCamera).transform.Find("ReFract_Volume");
				PostProcessVolume val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<PostProcessVolume>() : null);
				if ((Object)(object)val != (Object)null)
				{
					Debug.Log((object)$"[Re:Fract] Syncing PostProcess from '{((Object)val).GetInstanceID()}' to Capture Camera.");
					PostProcessVolume componentInChildren = ((Component)val).GetComponentInChildren<PostProcessVolume>();
					if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.profile != (Object)null)
					{
						int num = LayerMask.NameToLayer("Ignore Raycast");
						if ((Object)(object)val3 == (Object)null)
						{
							GameObject val4 = new GameObject("ReFract_Volume");
							val4.transform.SetParent(((Component)captureCamera).transform, false);
							val4.layer = num;
							val3 = val4.AddComponent<PostProcessVolume>();
							BoxCollider obj = val4.AddComponent<BoxCollider>();
							((Collider)obj).isTrigger = true;
							obj.size = Vector3.one * 0.01f;
							val3.isGlobal = false;
						}
						if ((Object)(object)component != (Object)null)
						{
							((Behaviour)component).enabled = false;
						}
						((Behaviour)val3).enabled = true;
						PostProcessProfile val5 = Object.Instantiate<PostProcessProfile>(componentInChildren.profile);
						MotionBlur setting = val5.GetSetting<MotionBlur>();
						if ((Object)(object)setting != (Object)null)
						{
							((ParameterOverride<bool>)(object)((PostProcessEffectSettings)setting).enabled).value = false;
						}
						val3.profile = val5;
						val3.weight = componentInChildren.weight;
						PostProcessLayer component2 = ((Component)captureCamera).GetComponent<PostProcessLayer>();
						if ((Object)(object)component2 != (Object)null)
						{
							component2.volumeLayer = LayerMask.op_Implicit(LayerMask.op_Implicit(component2.volumeLayer) | (1 << num));
							component2.volumeTrigger = ((Component)captureCamera).transform;
						}
					}
				}
				else
				{
					if ((Object)(object)component != (Object)null)
					{
						((Behaviour)component).enabled = false;
					}
					if ((Object)(object)val3 != (Object)null)
					{
						((Behaviour)val3).enabled = false;
					}
				}
			}

			[HarmonyPostfix]
			public static void Postfix(CameraRenderTask task, Camera __state)
			{
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__state == (Object)null || (Object)(object)__state.targetTexture == (Object)null || (!(_removeAlphaCameras.TryGetValue(((Object)__state.targetTexture).GetInstanceID(), out var value) && value) && !BoundConfig.forceRemoveAlpha.Value))
				{
					return;
				}
				try
				{
					Span<byte> span = RenderingManager.Instance.SharedMemory.AccessData<byte>(task.resultData);
					int num = 3;
					if (((object)(TextureFormat)(ref task.parameters.textureFormat)).ToString().IndexOf("ARGB", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						num = 0;
					}
					for (int i = num; i < span.Length; i += 4)
					{
						span[i] = byte.MaxValue;
					}
				}
				catch (Exception arg)
				{
					Debug.LogError((object)$"[Re:Fract] Failed to remove alpha: {arg}");
				}
			}
		}

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

			private object <>2__current;

			public ReFractCommand command;

			public Plugin <>4__this;

			private int <i>5__2;

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

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

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

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

			private bool MoveNext()
			{
				int num = <>1__state;
				Plugin plugin = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<i>5__2 = 0;
					break;
				case 1:
					<>1__state = -1;
					<i>5__2++;
					break;
				}
				if (<i>5__2 < 5)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				RenderTextureAsset asset = RenderingManager.Instance.RenderTextures.GetAsset(command.RenderTextureId);
				if ((Object)(object)((asset != null) ? asset.Texture : null) == (Object)null)
				{
					return false;
				}
				if (command.IsRemoveAlphaCommand)
				{
					_removeAlphaCameras[((Object)asset.Texture).GetInstanceID()] = command.BoolValue;
				}
				List<Camera> list = FindCamerasRenderingTo(asset.Texture);
				if (list.Count > 0)
				{
					_cameraCache[command.RenderTextureId] = list;
					DoDebugLog($"[Re:Fract] Found {list.Count} cameras after waiting.");
					foreach (Camera item in list)
					{
						plugin.EnsurePostProcessVolume(item);
						if (!command.IsRemoveAlphaCommand)
						{
							plugin.ApplyCommand(item, command);
						}
					}
				}
				else
				{
					Debug.LogWarning((object)"[Re:Fract] ...still no camera found after waiting.");
				}
				return false;
			}

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

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

		private Messenger _msg;

		private static readonly Dictionary<int, List<Camera>> _cameraCache = new Dictionary<int, List<Camera>>();

		private static readonly Dictionary<int, bool> _removeAlphaCameras = new Dictionary<int, bool>();

		private readonly ConcurrentQueue<Action> _mainThreadQueue = new ConcurrentQueue<Action>();

		public static Dictionary<string, Type> TypeLookups = new Dictionary<string, Type>
		{
			{
				"AmbientOcclusion",
				typeof(AmbientOcclusion)
			},
			{
				"AutoExposure",
				typeof(AutoExposure)
			},
			{
				"Bloom",
				typeof(Bloom)
			},
			{
				"ChromaticAberration",
				typeof(ChromaticAberration)
			},
			{
				"ColorGrading",
				typeof(ColorGrading)
			},
			{
				"DepthOfField",
				typeof(DepthOfField)
			},
			{
				"Grain",
				typeof(Grain)
			},
			{
				"LensDistortion",
				typeof(LensDistortion)
			},
			{
				"MotionBlur",
				typeof(MotionBlur)
			},
			{
				"ScreenSpaceReflections",
				typeof(ScreenSpaceReflections)
			},
			{
				"Vignette",
				typeof(Vignette)
			},
			{
				"AmplifyOcclusionBase",
				typeof(AmplifyOcclusionBase)
			}
		};

		internal static ReFractConfig BoundConfig { get; private set; } = null;


		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)"[Re:Fract] Binding configs");
			BoundConfig = new ReFractConfig(((BaseUnityPlugin)this).Config);
			Debug.Log((object)"[Re:Fract] Setting up interprocess");
			_msg = new Messenger("dog.glacier.ReFract", new List<Type>(1) { typeof(ReFractCommand) }, (List<Type>)null);
			_msg.ReceiveObject<ReFractCommand>("SetVariable", (Action<ReFractCommand>)HandleSetVariable);
			BepInExExtensions.SyncConfigEntry<bool>(_msg, BoundConfig.debugLogging);
			BepInExExtensions.SyncConfigEntry<bool>(_msg, BoundConfig.forceRemoveAlpha);
			Debug.Log((object)"[Re:Fract] Running harmony patches!");
			new Harmony("dog.glacier.ReFractUnity").PatchAll();
		}

		private void Update()
		{
			Action result;
			while (_mainThreadQueue.TryDequeue(out result))
			{
				result();
			}
		}

		private static void DoDebugLog(string input)
		{
			if (BoundConfig.debugLogging.Value)
			{
				Debug.Log((object)input);
			}
		}

		private void HandleSetVariable(ReFractCommand command)
		{
			ReFractCommand command2 = command;
			_mainThreadQueue.Enqueue(delegate
			{
				HandleSetVariableInternal(command2);
			});
		}

		private void HandleSetVariableInternal(ReFractCommand command)
		{
			DoDebugLog($"[Re:Fract] Received command for RT ID: {command.RenderTextureId}");
			if (command.RenderTextureId == 0)
			{
				Debug.LogWarning((object)"[Re:Fract] ERROR: Command has a zero RenderTextureId. Ignoring.");
				return;
			}
			RenderTextureAsset asset = RenderingManager.Instance.RenderTextures.GetAsset(command.RenderTextureId);
			if ((Object)(object)((asset != null) ? asset.Texture : null) != (Object)null && command.IsRemoveAlphaCommand)
			{
				int instanceID = ((Object)asset.Texture).GetInstanceID();
				DoDebugLog($"[Re:Fract] Setting RemoveAlpha for Unity Texture {instanceID} (Resonite {command.RenderTextureId}) to {command.BoolValue}");
				_removeAlphaCameras[instanceID] = command.BoolValue;
			}
			if (!_cameraCache.TryGetValue(command.RenderTextureId, out List<Camera> value) || value == null)
			{
				DoDebugLog($"[Re:Fract] Camera for {command.RenderTextureId} not in cache or is null. Searching...");
				if ((Object)(object)((asset != null) ? asset.Texture : null) == (Object)null)
				{
					if (command.IsRemoveAlphaCommand)
					{
						((MonoBehaviour)this).StartCoroutine(WaitForCameraAndApply(command));
					}
					return;
				}
				DoDebugLog($"[Re:Fract] Found render texture asset for {command.RenderTextureId}");
				value = FindCamerasRenderingTo(asset.Texture);
				if (value.Count == 0)
				{
					Debug.LogWarning((object)"[Re:Fract] ...but no camera was found. Waiting a few frames...");
					((MonoBehaviour)this).StartCoroutine(WaitForCameraAndApply(command));
					return;
				}
				_cameraCache[command.RenderTextureId] = value;
				DoDebugLog($"[Re:Fract] Found and cached {value.Count} cameras for ID {command.RenderTextureId}");
			}
			else
			{
				DoDebugLog($"[Re:Fract] Using cached cameras for ID {command.RenderTextureId}");
				if (command.IsRemoveAlphaCommand && value.Count > 0 && (Object)(object)value[0].targetTexture != (Object)null)
				{
					_removeAlphaCameras[((Object)value[0].targetTexture).GetInstanceID()] = command.BoolValue;
				}
			}
			value.RemoveAll((Camera c) => (Object)(object)c == (Object)null);
			if (value.Count == 0)
			{
				Debug.LogWarning((object)$"[Re:Fract] ERROR: All cached cameras for {command.RenderTextureId} were destroyed. Removing from cache.");
				if ((Object)(object)((asset != null) ? asset.Texture : null) != (Object)null)
				{
					_removeAlphaCameras.Remove(((Object)asset.Texture).GetInstanceID());
				}
				_cameraCache.Remove(command.RenderTextureId);
				return;
			}
			foreach (Camera item in value)
			{
				EnsurePostProcessVolume(item);
				if (!command.IsRemoveAlphaCommand)
				{
					ApplyCommand(item, command);
				}
			}
		}

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

		private void EnsurePostProcessVolume(Camera camera)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			ReFractVolumeTracker reFractVolumeTracker = ((Component)camera).gameObject.GetComponent<ReFractVolumeTracker>();
			if ((Object)(object)reFractVolumeTracker == (Object)null)
			{
				reFractVolumeTracker = ((Component)camera).gameObject.AddComponent<ReFractVolumeTracker>();
			}
			int num = LayerMask.NameToLayer("Ignore Raycast");
			PostProcessLayer component = ((Component)camera).gameObject.GetComponent<PostProcessLayer>();
			if ((Object)(object)component != (Object)null)
			{
				component.volumeTrigger = ((Component)camera).transform;
				int num2 = 1 << num;
				if ((LayerMask.op_Implicit(component.volumeLayer) & num2) == 0)
				{
					DoDebugLog($"[Re:Fract] PostProcessLayer volumeLayer mask mismatch. Adding layer {num} (Ignore Raycast).");
					component.volumeLayer = LayerMask.op_Implicit(LayerMask.op_Implicit(component.volumeLayer) | num2);
				}
			}
			PostProcessVolume component2 = ((Component)camera).GetComponent<PostProcessVolume>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			BoxCollider component3 = ((Component)camera).GetComponent<BoxCollider>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.Destroy((Object)(object)component3);
			}
			Transform val = ((Component)camera).transform.Find("ReFract_Volume");
			if ((Object)(object)val == (Object)null)
			{
				GameObject val2 = new GameObject("ReFract_Volume");
				val2.transform.SetParent(((Component)camera).transform, false);
				val2.layer = num;
				val = val2.transform;
			}
			reFractVolumeTracker.VolumeObject = ((Component)val).gameObject;
			PostProcessVolume val3 = ((Component)val).GetComponent<PostProcessVolume>();
			if ((Object)(object)val3 == (Object)null)
			{
				DoDebugLog("[Re:Fract] Creating PostProcessVolume on child of '" + ((Object)camera).name + "'.");
				val3 = ((Component)val).gameObject.AddComponent<PostProcessVolume>();
			}
			val3.isGlobal = false;
			if ((Object)(object)((Component)val).GetComponent<BoxCollider>() == (Object)null)
			{
				BoxCollider obj = ((Component)val).gameObject.AddComponent<BoxCollider>();
				((Collider)obj).isTrigger = true;
				obj.size = Vector3.one * 0.01f;
			}
			string text = $"ReFract_Profile_{((Object)camera).GetInstanceID()}";
			if ((Object)(object)val3.profile == (Object)null)
			{
				DoDebugLog("[Re:Fract] PostProcessVolume on '" + ((Object)camera).name + "' has no profile. Creating one and adding all settings.");
				PostProcessProfile val4 = ScriptableObject.CreateInstance<PostProcessProfile>();
				((Object)val4).name = text;
				val3.profile = val4;
				foreach (Type value in TypeLookups.Values)
				{
					if (typeof(PostProcessEffectSettings).IsAssignableFrom(value))
					{
						DoDebugLog("[Re:Fract] Adding setting '" + value.Name + "' to new profile.");
						val3.profile.AddSettings(value);
					}
				}
			}
			else if (((Object)val3.profile).name != text)
			{
				DoDebugLog("[Re:Fract] Ensuring unique profile for '" + ((Object)camera).name + "'.");
				PostProcessProfile val5 = Object.Instantiate<PostProcessProfile>(val3.profile);
				((Object)val5).name = text;
				val3.profile = val5;
				foreach (Type value2 in TypeLookups.Values)
				{
					if (typeof(PostProcessEffectSettings).IsAssignableFrom(value2) && !val5.HasSettings(value2))
					{
						val5.AddSettings(value2);
					}
				}
			}
			ColorGrading val6 = default(ColorGrading);
			if (val3.profile.TryGetSettings<ColorGrading>(ref val6))
			{
				((ParameterOverride<GradingMode>)(object)val6.gradingMode).value = (GradingMode)1;
				((ParameterOverride)val6.gradingMode).overrideState = true;
			}
		}

		private void ApplyCommand(Camera camera, ReFractCommand command)
		{
			DoDebugLog("[Re:Fract] Searching for component '" + command.ComponentName + "' on camera '" + ((Object)camera).name + "'");
			object obj = null;
			if (!TypeLookups.TryGetValue(command.ComponentName, out Type value))
			{
				Debug.LogWarning((object)("[Re:Fract] Unsupported Type " + command.ComponentName));
				return;
			}
			if (typeof(PostProcessEffectSettings).IsAssignableFrom(value))
			{
				PostProcessVolume componentInChildren = ((Component)camera).GetComponentInChildren<PostProcessVolume>();
				if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.profile != (Object)null)
				{
					foreach (PostProcessEffectSettings setting in componentInChildren.profile.settings)
					{
						if (((object)setting).GetType() == value)
						{
							obj = setting;
							break;
						}
					}
					if (obj == null)
					{
						obj = componentInChildren.profile.AddSettings(value);
					}
				}
			}
			else
			{
				obj = ((Component)camera).GetComponent(value);
			}
			if (obj == null)
			{
				Debug.LogWarning((object)("[Re:Fract] ERROR: Camera '" + ((Object)camera).name + "' does not have or could not create component '" + command.ComponentName + "'"));
				return;
			}
			DoDebugLog("[Re:Fract] Found target '" + command.ComponentName + "'");
			object valueFromCommand = GetValueFromCommand(command);
			Type type = obj.GetType();
			if (command.ParameterName.EndsWith("!"))
			{
				string text = command.ParameterName.Substring(0, command.ParameterName.Length - 1);
				DoDebugLog($"[Re:Fract] Attempting to set property '{text}' on '{command.ComponentName} ({type.FullName})' to value '{valueFromCommand}'");
				Action<object, object> propSetter = Introspection.GetPropSetter(type, text);
				if (propSetter != null)
				{
					propSetter(obj, valueFromCommand);
					DoDebugLog("[Re:Fract] SUCCESS: Set property '" + text + "'.");
					return;
				}
				Debug.LogWarning((object)("[Re:Fract] ERROR: Could not find writable property '" + text + "' on component '" + command.ComponentName + "'"));
				return;
			}
			DoDebugLog($"[Re:Fract] Attempting to set '{command.ParameterName}' on '{command.ComponentName} ({type.FullName})' to value '{valueFromCommand}'");
			FieldInfo field = type.GetField(command.ParameterName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && typeof(ParameterOverride).IsAssignableFrom(field.FieldType))
			{
				object value2 = field.GetValue(obj);
				if (value2 != null)
				{
					Type type2 = value2.GetType();
					bool flag = false;
					FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.Public);
					if (field2 != null)
					{
						try
						{
							field2.SetValue(value2, valueFromCommand);
							DoDebugLog("[Re:Fract] Set 'value' field on ParameterOverride '" + command.ParameterName + "'.");
							flag = true;
						}
						catch (Exception arg)
						{
							Debug.LogWarning((object)$"[Re:Fract] Failed to set ParameterOverride field value: {arg}");
						}
					}
					if (!flag)
					{
						PropertyInfo property = type2.GetProperty("value");
						if (property != null && property.CanWrite)
						{
							try
							{
								property.SetValue(value2, valueFromCommand);
								DoDebugLog("[Re:Fract] Set 'value' property on ParameterOverride '" + command.ParameterName + "'.");
								flag = true;
							}
							catch (Exception arg2)
							{
								Debug.LogWarning((object)$"[Re:Fract] Failed to set ParameterOverride property value: {arg2}");
							}
						}
					}
					if (flag)
					{
						FieldInfo field3 = type2.GetField("overrideState", BindingFlags.Instance | BindingFlags.Public);
						if (field3 != null)
						{
							field3.SetValue(value2, true);
							DoDebugLog("[Re:Fract] SUCCESS: Activated override for '" + command.ParameterName + "'.");
						}
						else
						{
							Debug.LogWarning((object)("[Re:Fract] Could not find 'overrideState' field on '" + type2.Name + "'. The setting may not apply visually."));
						}
						return;
					}
				}
			}
			Action<object, object> propSetter2 = Introspection.GetPropSetter(type, command.ParameterName);
			if (propSetter2 != null)
			{
				propSetter2(obj, valueFromCommand);
				DoDebugLog("[Re:Fract] SUCCESS: Set property '" + command.ParameterName + "'.");
				return;
			}
			Introspection.RefAction<object, object> fieldSetter = Introspection.GetFieldSetter(type, command.ParameterName);
			if (fieldSetter != null)
			{
				fieldSetter(ref obj, valueFromCommand);
				DoDebugLog("[Re:Fract] SUCCESS: Set field '" + command.ParameterName + "'.");
				return;
			}
			Debug.LogWarning((object)("[Re:Fract] ERROR: Could not find writable property or field '" + command.ParameterName + "' on component '" + command.ComponentName + "'"));
		}

		private static object GetValueFromCommand(ReFractCommand command)
		{
			//IL_007e: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			return command.ValueType switch
			{
				ReFractCommandValueType.Int => command.IntValue, 
				ReFractCommandValueType.Float => command.FloatValue, 
				ReFractCommandValueType.Bool => command.BoolValue, 
				ReFractCommandValueType.Color => (object)new Color(command.ColorValue.r, command.ColorValue.g, command.ColorValue.b, command.ColorValue.a), 
				ReFractCommandValueType.Vector2 => (object)new Vector2(command.Vector2Value.x, command.Vector2Value.y), 
				ReFractCommandValueType.Vector4 => (object)new Vector4(command.Vector4Value.x, command.Vector4Value.y, command.Vector4Value.z, command.Vector4Value.w), 
				ReFractCommandValueType.String => command.StringValue, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		private static List<Camera> FindCamerasRenderingTo(RenderTexture target)
		{
			DoDebugLog(string.Format("[Re:Fract] Searching for RenderTexture {0} @ {1}", Object.op_Implicit((Object)(object)target) ? ((Object)target).name : "NULL TARGET", Object.op_Implicit((Object)(object)target) ? ((object)((Object)target).GetInstanceID()) : "N/A"));
			Camera[] array = Object.FindObjectsOfType<Camera>();
			List<Camera> list = new List<Camera>();
			Camera[] array2 = array;
			foreach (Camera val in array2)
			{
				DoDebugLog(string.Format("[Re:Fract] Camera {0} @ {1} --> {2} @ {3}...", ((Object)val).name, ((Object)val).GetInstanceID(), Object.op_Implicit((Object)(object)val.targetTexture) ? ((Object)val.targetTexture).name : "NULL TARGET", Object.op_Implicit((Object)(object)val.targetTexture) ? ((object)((Object)val.targetTexture).GetInstanceID()) : "N/A"));
				if ((Object)(object)val.targetTexture == (Object)(object)target)
				{
					list.Add(val);
				}
			}
			if (list.Count == 0)
			{
				Debug.LogWarning((object)"[Re:Fract] No camera found rendering to the specified RenderTexture.");
			}
			return list;
		}
	}
}