Decompiled source of FATE CameraTurn v0.1.1

BepInEx/plugins/PartGhostCameraTurn/PartGhost.FateCameraTurn.dll

Decompiled 5 days ago
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Cleverous.Prodigy;
using Cleverous.Prodigy.Input;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Tableflip;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PartGhost")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 PartGhost")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("PartGhost.FateCameraTurn")]
[assembly: AssemblyTitle("PartGhost.FateCameraTurn")]
[assembly: AssemblyVersion("0.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 PartGhost.FateControls
{
	internal static class ControlsCommon
	{
		internal sealed class LegacyGate
		{
			private readonly MethodBase target;

			private readonly string patch;

			private float nextCheck = float.NegativeInfinity;

			internal bool Owns { get; private set; } = true;

			internal LegacyGate(Type gameType, string method, string patch)
			{
				target = AccessTools.Method(gameType, method, (Type[])null, (Type[])null);
				this.patch = patch;
			}

			internal void Refresh()
			{
				if (!(Time.unscaledTime < nextCheck))
				{
					nextCheck = Time.unscaledTime + 1f;
					Patches val = ((target == null) ? null : Harmony.GetPatchInfo(target));
					Owns = val == null || !val.Prefixes.Concat(val.Postfixes).Any((Patch p) => p.owner == "local.fatecoop.prototype" && p.PatchMethod.Name == patch);
				}
			}
		}

		private static Type rebindApi;

		private static Func<bool> rebindBlocked;

		private static FieldInfo legacyActive;

		private static FieldInfo legacyDowned;

		private static bool dependenciesDirty;

		internal static Type Api => rebindApi;

		internal static bool Blocked
		{
			get
			{
				if (!InputBlocker.AnyBlockingUiMenuIsOpen && !InventoryUI.IsDraggingItem && !LegacyDowned)
				{
					return rebindBlocked?.Invoke() ?? false;
				}
				return true;
			}
		}

		private static bool LegacyDowned
		{
			get
			{
				if (legacyActive == null || legacyDowned == null)
				{
					return false;
				}
				object value = legacyActive.GetValue(null);
				if (value != null)
				{
					return (bool)legacyDowned.GetValue(value);
				}
				return false;
			}
		}

		static ControlsCommon()
		{
			dependenciesDirty = true;
			AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
		}

		private static void AssemblyLoaded(object sender, AssemblyLoadEventArgs e)
		{
			dependenciesDirty = true;
		}

		internal static void Prepare()
		{
			if (dependenciesDirty)
			{
				dependenciesDirty = false;
				Type type = null;
				rebindApi = null;
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					rebindApi = rebindApi ?? assembly.GetType("ZombieGhost.Rebind.RebindApi", throwOnError: false);
					type = type ?? assembly.GetType("FateCoop.Prototype.Plugin", throwOnError: false);
				}
				MethodInfo methodInfo = rebindApi?.GetProperty("IsInputBlocked")?.GetGetMethod();
				rebindBlocked = ((methodInfo == null) ? null : ((Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), methodInfo)));
				legacyActive = ((type == null) ? null : AccessTools.Field(type, "Active"));
				legacyDowned = ((type == null) ? null : AccessTools.Field(type, "downed"));
			}
		}

		internal static object Register(string guid, string name, params (string id, InputAction action, string label, string category)[] actions)
		{
			Type api = Api;
			if (api == null)
			{
				return null;
			}
			object obj = api.GetMethod("RegisterProvider").Invoke(null, new object[2] { guid, name });
			try
			{
				for (int i = 0; i < actions.Length; i++)
				{
					(string, InputAction, string, string) tuple = actions[i];
					obj.GetType().GetMethod("RegisterAction").Invoke(obj, new object[5] { tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, null });
				}
				return obj;
			}
			catch
			{
				(obj as IDisposable)?.Dispose();
				throw;
			}
		}

		internal static void Hook(Harmony harmony, Type source, string targetType, string method, string prefix = null, string postfix = null)
		{
			//IL_0025: 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)
			MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName(targetType), method, (Type[])null, (Type[])null) ?? throw new MissingMethodException(targetType, method);
			harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(source, prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(source, postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		internal static InputAction Button(string name, string path)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			InputAction val = new InputAction(name, (InputActionType)1, path, (string)null, (string)null, "Button");
			val.Enable();
			return val;
		}
	}
	[BepInPlugin("partghost.fate.cameraturn", "FATE Camera Turn", "0.1.1")]
	public sealed class CameraTurnPlugin : BaseUnityPlugin
	{
		public const string Guid = "partghost.fate.cameraturn";

		private static CameraTurnPlugin active;

		private Harmony harmony;

		private InputAction drag;

		private object provider;

		private ConfigEntry<float> speed;

		private float yaw;

		private Vector2 start;

		private bool dragging;

		private bool legacyWarned;

		private ProdigyCamera cameraOwner;

		private ControlsCommon.LegacyGate legacy;

		private static readonly FieldRef<ProdigyCamera, Quaternion> OriginalRotation = AccessTools.FieldRefAccess<ProdigyCamera, Quaternion>("originalRotation");

		private static readonly FieldRef<ProdigyCamera, float> OriginalYaw = AccessTools.FieldRefAccess<ProdigyCamera, float>("originalYRotation");

		private static readonly FieldRef<MiniMapIconUI, Quaternion> SavedRotation = AccessTools.FieldRefAccess<MiniMapIconUI, Quaternion>("savedRotation");

		private void Awake()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			if (!((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "Enabled", true, "Enable mouse-drag camera turning.").Value)
			{
				return;
			}
			active = this;
			speed = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "CameraTurnSpeed", 0.25f, new ConfigDescription("Degrees per pixel while the camera turn button is held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), Array.Empty<object>()));
			drag = ControlsCommon.Button("camera.drag", "<Mouse>/middleButton");
			harmony = new Harmony("partghost.fate.cameraturn");
			legacy = new ControlsCommon.LegacyGate(typeof(ProdigyCamera), "UpdateCameraRotation", "BeforeCameraRotation");
			try
			{
				ControlsCommon.Hook(harmony, typeof(CameraTurnPlugin), typeof(ProdigyCamera).FullName, "UpdateCameraRotation", "Rotate");
				ControlsCommon.Hook(harmony, typeof(CameraTurnPlugin), typeof(MiniMapIconUI).FullName, "LateUpdate", null, "Minimap");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"FATE Camera Turn 0.1.1 ready; standalone controls.");
			}
			catch (Exception ex)
			{
				harmony.UnpatchSelf();
				active = null;
				drag.Dispose();
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private bool Owns()
		{
			if (legacy.Owns)
			{
				return true;
			}
			if (!legacyWarned)
			{
				legacyWarned = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Original co-op camera controls installed. Standalone camera suspended; set its Controls.KeyboardMovement=false and restart.");
			}
			return false;
		}

		private static bool Rotate(ProdigyCamera __instance)
		{
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			CameraTurnPlugin cameraTurnPlugin = active;
			if (cameraTurnPlugin == null)
			{
				return true;
			}
			ControlsCommon.Prepare();
			cameraTurnPlugin.legacy.Refresh();
			if (!cameraTurnPlugin.Owns())
			{
				return true;
			}
			if (cameraTurnPlugin.provider == null && ControlsCommon.Api != null)
			{
				cameraTurnPlugin.provider = ControlsCommon.Register("partghost.fate.cameraturn", "Camera Turn", ("drag", cameraTurnPlugin.drag, "Hold to turn camera", "Camera"));
			}
			if ((Object)(object)cameraTurnPlugin.cameraOwner != (Object)(object)__instance)
			{
				cameraTurnPlugin.cameraOwner = __instance;
				cameraTurnPlugin.yaw = 0f;
				cameraTurnPlugin.dragging = false;
			}
			Mouse current = Mouse.current;
			InputBroker instance = SingletonBehaviour<InputBroker>.Instance;
			if (ControlsCommon.Blocked)
			{
				cameraTurnPlugin.dragging = false;
				return false;
			}
			if (cameraTurnPlugin.drag.IsPressed())
			{
				if (!cameraTurnPlugin.dragging)
				{
					cameraTurnPlugin.start = ((current != null) ? ((InputControl<Vector2>)(object)((Pointer)current).position).ReadValue() : Vector2.zero);
					cameraTurnPlugin.dragging = true;
				}
				if (current != null)
				{
					cameraTurnPlugin.yaw += ((InputControl<Vector2>)(object)((Pointer)current).delta).ReadValue().x * cameraTurnPlugin.speed.Value;
				}
			}
			else if (cameraTurnPlugin.dragging)
			{
				if (current != null)
				{
					current.WarpCursorPosition(cameraTurnPlugin.start);
				}
				cameraTurnPlugin.dragging = false;
			}
			if ((Object)(object)instance != (Object)null && !instance.HoldingSpellWheel)
			{
				cameraTurnPlugin.yaw -= instance.CameraRotateInputValue * 120f * Time.unscaledDeltaTime;
			}
			cameraTurnPlugin.yaw = Mathf.Repeat(cameraTurnPlugin.yaw + 180f, 360f) - 180f;
			Vector3 eulerAngles = ((Quaternion)(ref OriginalRotation.Invoke(__instance))).eulerAngles;
			((Component)__instance).transform.localRotation = Quaternion.Euler(eulerAngles.x, OriginalYaw.Invoke(__instance) + cameraTurnPlugin.yaw, eulerAngles.z);
			return false;
		}

		private static void Minimap(MiniMapIconUI __instance)
		{
			//IL_002a: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			CameraTurnPlugin cameraTurnPlugin = active;
			if (cameraTurnPlugin != null && cameraTurnPlugin.Owns() && !((Object)(object)ProdigyCamera.GameCamera == (Object)null))
			{
				Quaternion val = SavedRotation.Invoke(__instance);
				if (__instance.isCamera)
				{
					((Component)__instance).transform.rotation = Quaternion.AngleAxis(cameraTurnPlugin.yaw, Vector3.up) * val;
					return;
				}
				Vector3 val2 = val * Vector3.up;
				float num = Mathf.Atan2(val2.x, val2.z) * 57.29578f;
				((Component)__instance).transform.rotation = Quaternion.AngleAxis(((Component)ProdigyCamera.GameCamera).transform.eulerAngles.y - num, Vector3.up) * val;
			}
		}

		private void OnApplicationQuit()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			(provider as IDisposable)?.Dispose();
			InputAction obj2 = drag;
			if (obj2 != null)
			{
				obj2.Dispose();
			}
			active = null;
		}
	}
}