Decompiled source of Empress First Person v0.1.1

BepInEx/plugins/Empress.FirstPerson/Empress.FirstPerson.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LazyBearTechnology;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Empress.FirstPerson;

[DefaultExecutionOrder(32000)]
internal sealed class FirstPersonService : MonoBehaviour
{
	private ViewSettings settings;

	private ManualLogSource log;

	private NativeMovementBridge movement;

	private NativeVisibilityBridge visibility;

	private SpriteWorld world;

	private FirstPersonView view;

	private PlayerController player;

	private Camera camera;

	private bool running;

	private bool enabledView;

	private bool lookEnabled;

	private bool ownsCursor;

	private CursorLockMode originalCursorLock;

	private bool originalCursorVisible;

	private float yaw;

	private float pitch;

	internal bool IsActive
	{
		get
		{
			if (view != null)
			{
				return running;
			}
			return false;
		}
	}

	internal float Yaw => yaw;

	internal float Pitch => pitch;

	internal int ConvertedCount
	{
		get
		{
			if (world != null)
			{
				return world.ConvertedCount;
			}
			return 0;
		}
	}

	public void Initialize(ViewSettings configuration, ManualLogSource logger)
	{
		try
		{
			settings = configuration;
			log = logger;
			enabledView = settings.Enabled.Value;
			lookEnabled = settings.MouseLook.Value;
			world = new SpriteWorld();
			movement = new NativeMovementBridge(() => IsActive, () => yaw);
			visibility = new NativeVisibilityBridge(() => IsActive && GameBridge.IsGameplayReady(player), PrepareVisibility);
			SceneManager.sceneLoaded += OnSceneLoaded;
			running = true;
		}
		catch
		{
			Shutdown();
			throw;
		}
	}

	private void Update()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		if (!running)
		{
			return;
		}
		try
		{
			PlayerController val;
			Camera source;
			bool flag = GameBridge.TryGetPlayer(out val, out source) && GameBridge.IsGameplayReady(val);
			if (flag && Application.isFocused)
			{
				KeyboardShortcut value = settings.ToggleViewKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					enabledView = !enabledView;
				}
			}
			if (flag && Application.isFocused && Input.GetKeyDown((KeyCode)288))
			{
				lookEnabled = !lookEnabled;
			}
			if (!flag || !enabledView)
			{
				ReleaseView();
				return;
			}
			if ((Object)(object)player != (Object)(object)val || view == null || !view.Matches(source))
			{
				ReleaseView();
				player = val;
				camera = source;
				Vector2 animationDirection = val.View.GetAnimationDirection();
				yaw = ((((Vector2)(ref animationDirection)).sqrMagnitude > 0.001f) ? (Mathf.Atan2(animationDirection.x, animationDirection.y) * 57.29578f) : 0f);
				pitch = 0f;
				view = new FirstPersonView(camera);
			}
			bool flag2 = lookEnabled && Application.isFocused && GameBridge.CanLook(player);
			SetCursorCapture(flag2);
			if (flag2)
			{
				yaw = Mathf.Repeat(yaw + Input.GetAxisRaw("Mouse X") * settings.MouseSensitivity.Value, 360f);
				pitch = Mathf.Clamp(pitch - Input.GetAxisRaw("Mouse Y") * settings.MouseSensitivity.Value, -70f, 70f);
			}
		}
		catch (Exception error)
		{
			Fail(error);
		}
	}

	private void LateUpdate()
	{
		if (!running || view == null)
		{
			return;
		}
		try
		{
			if (!GameBridge.IsGameplayReady(player))
			{
				ReleaseView();
				return;
			}
			view.Apply(player, yaw, pitch, settings);
			world.Synchronize(camera, player);
			SetCursorCapture(lookEnabled && Application.isFocused && GameBridge.CanLook(player));
		}
		catch (Exception error)
		{
			Fail(error);
		}
	}

	private void OnGUI()
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		if (IsActive && GameBridge.CanLook(player))
		{
			GUI.Label(new Rect((float)Screen.width * 0.5f - 4f, (float)Screen.height * 0.5f - 10f, 20f, 20f), "+");
		}
	}

	private void PrepareVisibility()
	{
		try
		{
			if (view != null)
			{
				view.PrepareCamera(player, yaw, pitch, settings);
			}
		}
		catch (Exception error)
		{
			Fail(error);
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		ReleaseView();
		if (world != null)
		{
			world.Refresh();
		}
	}

	private void SetCursorCapture(bool capture)
	{
		//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_0041: Unknown result type (might be due to invalid IL or missing references)
		if (capture)
		{
			if (!ownsCursor)
			{
				originalCursorLock = Cursor.lockState;
				originalCursorVisible = Cursor.visible;
				ownsCursor = true;
			}
			Cursor.lockState = (CursorLockMode)1;
			Cursor.visible = false;
		}
		else if (!capture && ownsCursor)
		{
			Cursor.lockState = originalCursorLock;
			Cursor.visible = originalCursorVisible;
			ownsCursor = false;
		}
	}

	private void ReleaseView()
	{
		SetCursorCapture(capture: false);
		if (view != null)
		{
			view.Dispose();
			view = null;
		}
		if (world != null)
		{
			world.Refresh();
		}
		player = null;
		camera = null;
	}

	private void Fail(Exception error)
	{
		ReleaseView();
		running = false;
		if (visibility != null)
		{
			visibility.Dispose();
			visibility = null;
		}
		if (movement != null)
		{
			movement.Dispose();
			movement = null;
		}
		log.LogError((object)("First-person rendering stopped and the native view was restored: " + error));
	}

	public void Shutdown()
	{
		running = false;
		SceneManager.sceneLoaded -= OnSceneLoaded;
		ReleaseView();
		if (visibility != null)
		{
			visibility.Dispose();
			visibility = null;
		}
		if (movement != null)
		{
			movement.Dispose();
			movement = null;
		}
		if (world != null)
		{
			world.Dispose();
			world = null;
		}
	}

	private void OnDestroy()
	{
		Shutdown();
	}
}
internal sealed class FirstPersonView : IDisposable
{
	private readonly Camera camera;

	private readonly Vector3 localPosition;

	private readonly Quaternion localRotation;

	private readonly bool orthographic;

	private readonly float fieldOfView;

	private readonly float nearClip;

	private readonly float farClip;

	private readonly CameraClearFlags clearFlags;

	private readonly Color backgroundColor;

	private readonly Dictionary<Renderer, bool> playerVisibility = new Dictionary<Renderer, bool>();

	private bool disposed;

	public FirstPersonView(Camera source)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: 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_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_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		camera = source;
		localPosition = ((Component)source).transform.localPosition;
		localRotation = ((Component)source).transform.localRotation;
		orthographic = source.orthographic;
		fieldOfView = source.fieldOfView;
		nearClip = source.nearClipPlane;
		farClip = source.farClipPlane;
		clearFlags = source.clearFlags;
		backgroundColor = source.backgroundColor;
	}

	public bool Matches(Camera source)
	{
		if (!disposed)
		{
			return (Object)(object)camera == (Object)(object)source;
		}
		return false;
	}

	public void PrepareCamera(PlayerController player, float yaw, float pitch, ViewSettings settings)
	{
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		if (!disposed && !((Object)(object)camera == (Object)null))
		{
			camera.orthographic = false;
			camera.ResetProjectionMatrix();
			camera.fieldOfView = settings.FieldOfView.Value;
			camera.nearClipPlane = 0.035f;
			camera.farClipPlane = settings.ViewDistance.Value;
			Color val = default(Color);
			if (!ColorUtility.TryParseHtmlString(settings.HorizonColor.Value, ref val))
			{
				val = new Color(18f / 85f, 0.2627451f, 0.3372549f, 1f);
			}
			camera.clearFlags = (CameraClearFlags)2;
			camera.backgroundColor = val;
			((Component)camera).transform.SetPositionAndRotation(GameBridge.Position(player) + Vector3.up * settings.EyeHeight.Value, Quaternion.Euler(pitch, yaw, 0f));
		}
	}

	public void Apply(PlayerController player, float yaw, float pitch, ViewSettings settings)
	{
		PrepareCamera(player, yaw, pitch, settings);
		if (disposed || (Object)(object)camera == (Object)null || (Object)(object)player.View == (Object)null)
		{
			return;
		}
		Renderer[] componentsInChildren = ((Component)player.View).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null))
			{
				if (!playerVisibility.ContainsKey(val))
				{
					playerVisibility.Add(val, val.forceRenderingOff);
				}
				val.forceRenderingOff = true;
			}
		}
	}

	public void Dispose()
	{
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		if (disposed)
		{
			return;
		}
		disposed = true;
		foreach (KeyValuePair<Renderer, bool> item in playerVisibility)
		{
			if ((Object)(object)item.Key != (Object)null)
			{
				item.Key.forceRenderingOff = item.Value;
			}
		}
		playerVisibility.Clear();
		if (!((Object)(object)camera == (Object)null))
		{
			camera.orthographic = orthographic;
			camera.ResetProjectionMatrix();
			camera.fieldOfView = fieldOfView;
			camera.nearClipPlane = nearClip;
			camera.farClipPlane = farClip;
			camera.clearFlags = clearFlags;
			camera.backgroundColor = backgroundColor;
			((Component)camera).transform.localPosition = localPosition;
			((Component)camera).transform.localRotation = localRotation;
		}
	}
}
internal static class GameBridge
{
	public static bool TryGetPlayer(out PlayerController player, out Camera camera)
	{
		player = CurrentPlayer();
		camera = null;
		if (!IsGameplayReady(player))
		{
			return false;
		}
		CameraSystem instance = CameraSystem.Instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)instance.MainCamera == (Object)null)
		{
			return false;
		}
		camera = instance.WorldCamera;
		if ((Object)(object)camera != (Object)null)
		{
			return ((Component)camera).gameObject.activeInHierarchy;
		}
		return false;
	}

	public static Vector3 Position(PlayerController player)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)player != (Object)null) || !((Object)(object)player.PhysicalBody != (Object)null))
		{
			return Vector3.zero;
		}
		return ((Component)player.PhysicalBody).transform.position;
	}

	public static bool IsGameplayReady(PlayerController player)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Invalid comparison between Unknown and I4
		if ((Object)(object)MainGame.Instance != (Object)null && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)MainGame.PlayerController && (int)MainGame.Instance.gameState == 1 && !MainGame.IsGamePaused && Time.timeScale > 0f && player.IsControlsEnabled && (Object)(object)player.PhysicalBody != (Object)null && (Object)(object)player.View != (Object)null && ((Component)player.PhysicalBody).gameObject.activeInHierarchy)
		{
			return ((Component)player.View).gameObject.activeInHierarchy;
		}
		return false;
	}

	public static bool CanLook(PlayerController player)
	{
		if (IsGameplayReady(player) && Application.isFocused && player.IsControlsEnabled)
		{
			return !MouseAimHelper.IsPointerOverUI();
		}
		return false;
	}

	public static bool CanMove(PlayerController player)
	{
		if (IsGameplayReady(player) && Application.isFocused && player.IsControlsEnabled && player.Ssm != null)
		{
			return player.Ssm.CurState is FreePlayerState;
		}
		return false;
	}

	internal static PlayerController CurrentPlayer()
	{
		if (!((Object)(object)MainGame.Instance == (Object)null))
		{
			return MainGame.PlayerController;
		}
		return null;
	}
}
internal sealed class NativeMovementBridge : IDisposable
{
	private const string PatchIdentifier = "empress.graveyardkeeper2.firstperson.input";

	private static NativeMovementBridge active;

	private readonly Func<bool> enabled;

	private readonly Func<float> yaw;

	private readonly Harmony harmony;

	private int scope;

	private bool disposed;

	public NativeMovementBridge(Func<bool> isEnabled, Func<float> currentYaw)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Expected O, but got Unknown
		//IL_0095: Expected O, but got Unknown
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Expected O, but got Unknown
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_010b: Expected O, but got Unknown
		if (isEnabled == null || currentYaw == null)
		{
			throw new ArgumentNullException("First-person input requires view state and yaw providers.");
		}
		if (active != null)
		{
			throw new InvalidOperationException("First-person input is already attached.");
		}
		enabled = isEnabled;
		yaw = currentYaw;
		harmony = new Harmony("empress.graveyardkeeper2.firstperson.input");
		try
		{
			harmony.Patch((MethodBase)AccessTools.Method(typeof(FreePlayerState), "FixedUpdate", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NativeMovementBridge), "BeginMovement", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(NativeMovementBridge), "EndMovement", (Type[])null), (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(LazyInput), "GetDirection", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(NativeMovementBridge), "RotateMovement", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(MouseAimHelper), "TryGetAimDirection", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NativeMovementBridge), "ReadAim", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			active = this;
		}
		catch
		{
			harmony.UnpatchSelf();
			throw;
		}
	}

	public void Dispose()
	{
		if (!disposed)
		{
			disposed = true;
			scope = 0;
			if (active == this)
			{
				active = null;
			}
			harmony.UnpatchSelf();
		}
	}

	private static void BeginMovement(FreePlayerState __instance, out NativeMovementBridge __state)
	{
		__state = null;
		NativeMovementBridge nativeMovementBridge = active;
		PlayerController val = GameBridge.CurrentPlayer();
		if (nativeMovementBridge != null && !nativeMovementBridge.disposed && nativeMovementBridge.enabled() && GameBridge.CanMove(val) && object.ReferenceEquals(val.Ssm.CurState, __instance))
		{
			nativeMovementBridge.scope++;
			__state = nativeMovementBridge;
		}
	}

	private static Exception EndMovement(Exception __exception, NativeMovementBridge __state)
	{
		if (__state != null)
		{
			__state.scope = Math.Max(0, __state.scope - 1);
		}
		return __exception;
	}

	private static void RotateMovement(ref Vector2 __result)
	{
		//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)
		NativeMovementBridge nativeMovementBridge = active;
		if (nativeMovementBridge != null && !nativeMovementBridge.disposed && nativeMovementBridge.scope != 0 && nativeMovementBridge.enabled() && GameBridge.CanMove(GameBridge.CurrentPlayer()))
		{
			float num = nativeMovementBridge.yaw() * ((float)Math.PI / 180f);
			if (!float.IsNaN(num) && !float.IsInfinity(num))
			{
				float num2 = Mathf.Sin(num);
				float num3 = Mathf.Cos(num);
				__result = new Vector2(num3 * __result.x + num2 * __result.y, (0f - num2) * __result.x + num3 * __result.y);
			}
		}
	}

	private static bool ReadAim(Vector3 __0, ref Vector2 __1, ref bool __result)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		NativeMovementBridge nativeMovementBridge = active;
		PlayerController player = GameBridge.CurrentPlayer();
		if (nativeMovementBridge != null && !nativeMovementBridge.disposed && nativeMovementBridge.enabled() && GameBridge.CanLook(player))
		{
			Vector3 val = __0 - GameBridge.Position(player);
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.0001f))
			{
				float num = nativeMovementBridge.yaw() * ((float)Math.PI / 180f);
				if (float.IsNaN(num) || float.IsInfinity(num))
				{
					return true;
				}
				Vector2 val2 = new Vector2(Mathf.Sin(num), Mathf.Cos(num) * 1.25f);
				__1 = ((Vector2)(ref val2)).normalized;
				__result = true;
				return false;
			}
		}
		return true;
	}
}
internal sealed class NativeVisibilityBridge : IDisposable
{
	private const string PatchIdentifier = "empress.graveyardkeeper2.firstperson.visibility";

	private static NativeVisibilityBridge active;

	private readonly Func<bool> enabled;

	private readonly Action applyCamera;

	private readonly Harmony harmony;

	private bool preparing;

	private bool disposed;

	public NativeVisibilityBridge(Func<bool> isEnabled, Action prepareCamera)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Expected O, but got Unknown
		if (isEnabled == null || prepareCamera == null)
		{
			throw new ArgumentNullException("First-person visibility requires view state and camera providers.");
		}
		if (active != null)
		{
			throw new InvalidOperationException("First-person visibility is already attached.");
		}
		enabled = isEnabled;
		applyCamera = prepareCamera;
		harmony = new Harmony("empress.graveyardkeeper2.firstperson.visibility");
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(ChunkManager), "TryProcessChunkVisibility", Type.EmptyTypes, (Type[])null);
			if (methodInfo == null)
			{
				throw new MissingMethodException(typeof(ChunkManager).FullName, "TryProcessChunkVisibility");
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(NativeVisibilityBridge), "PrepareCamera", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			active = this;
		}
		catch
		{
			harmony.UnpatchSelf();
			throw;
		}
	}

	public void Dispose()
	{
		if (!disposed)
		{
			disposed = true;
			if (active == this)
			{
				active = null;
			}
			harmony.UnpatchSelf();
		}
	}

	[HarmonyPriority(800)]
	private static void PrepareCamera()
	{
		NativeVisibilityBridge nativeVisibilityBridge = active;
		if (nativeVisibilityBridge == null || nativeVisibilityBridge.disposed || nativeVisibilityBridge.preparing || !nativeVisibilityBridge.enabled())
		{
			return;
		}
		nativeVisibilityBridge.preparing = true;
		try
		{
			nativeVisibilityBridge.applyCamera();
		}
		finally
		{
			nativeVisibilityBridge.preparing = false;
		}
	}
}
[BepInPlugin("empress.graveyardkeeper2.firstperson", "Empress First Person", "0.1.1")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Identifier = "empress.graveyardkeeper2.firstperson";

	private FirstPersonService service;

	private GameObject serviceHost;

	private void Awake()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		try
		{
			ViewSettings configuration = new ViewSettings(((BaseUnityPlugin)this).Config);
			serviceHost = new GameObject("Empress First Person");
			Object.DontDestroyOnLoad((Object)(object)serviceHost);
			service = serviceHost.AddComponent<FirstPersonService>();
			service.Initialize(configuration, ((BaseUnityPlugin)this).Logger);
		}
		catch
		{
			if ((Object)(object)serviceHost != (Object)null)
			{
				Object.Destroy((Object)(object)serviceHost);
			}
			service = null;
			serviceHost = null;
			throw;
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)service != (Object)null)
		{
			service.Shutdown();
		}
		if ((Object)(object)serviceHost != (Object)null)
		{
			Object.Destroy((Object)(object)serviceHost);
		}
	}
}
internal sealed class ViewSettings
{
	public readonly ConfigEntry<bool> Enabled;

	public readonly ConfigEntry<float> FieldOfView;

	public readonly ConfigEntry<float> EyeHeight;

	public readonly ConfigEntry<float> MouseSensitivity;

	public readonly ConfigEntry<bool> MouseLook;

	public readonly ConfigEntry<string> HorizonColor;

	public readonly ConfigEntry<KeyboardShortcut> ToggleViewKey;

	public readonly ConfigEntry<float> ViewDistance;

	public ViewSettings(ConfigFile config)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Expected O, but got Unknown
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Expected O, but got Unknown
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Expected O, but got Unknown
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		Enabled = config.Bind<bool>("General", "Enabled", true, "Enable the first-person view on startup during free gameplay.");
		FieldOfView = config.Bind<float>("View", "FieldOfView", 70f, new ConfigDescription("Vertical field of view.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(45f, 100f), new object[0]));
		ViewDistance = config.Bind<float>("View", "ViewDistance", 50f, new ConfigDescription("First-person draw distance in world units.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 120f), new object[0]));
		EyeHeight = config.Bind<float>("View", "EyeHeight", 0.8f, new ConfigDescription("Camera height above the physical player position.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 2.5f), new object[0]));
		HorizonColor = config.Bind<string>("View", "HorizonColor", "#364356", "Solid horizon color in hexadecimal RGB notation.");
		MouseSensitivity = config.Bind<float>("Controls", "MouseSensitivity", 2f, new ConfigDescription("Mouse look sensitivity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 8f), new object[0]));
		MouseLook = config.Bind<bool>("Controls", "MouseLook", true, "Capture the mouse during free gameplay. F7 releases or captures it.");
		ToggleViewKey = config.Bind<KeyboardShortcut>("Controls", "ToggleViewKey", new KeyboardShortcut((KeyCode)277, (KeyCode[])(object)new KeyCode[0]), "Toggle first-person and the original view. Default: Insert.");
	}
}
internal sealed class SpriteWorld : IDisposable
{
	private sealed class Surface : IDisposable
	{
		private readonly SpriteRenderer renderer;

		private Material original;

		private Material owned;

		public Surface(SpriteRenderer source)
		{
			renderer = source;
			Synchronize();
		}

		public void Synchronize()
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			if ((Object)(object)renderer == (Object)null)
			{
				return;
			}
			Material sharedMaterial = ((Renderer)renderer).sharedMaterial;
			if ((Object)(object)sharedMaterial == (Object)(object)owned)
			{
				if ((Object)(object)owned != (Object)null)
				{
					owned.SetFloat("_ForceVertical", 1f);
					owned.EnableKeyword("FORCE_VERTICAL");
				}
				return;
			}
			if ((Object)(object)owned != (Object)null)
			{
				Object.Destroy((Object)(object)owned);
			}
			owned = null;
			original = sharedMaterial;
			if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null) && !(((Object)sharedMaterial.shader).name != "Custom/3D Sprite") && sharedMaterial.HasProperty("_ForceVertical"))
			{
				owned = new Material(sharedMaterial);
				((Object)owned).name = "Empress First Person Sprite";
				((Object)owned).hideFlags = (HideFlags)52;
				owned.SetFloat("_ForceVertical", 1f);
				owned.EnableKeyword("FORCE_VERTICAL");
				((Renderer)renderer).sharedMaterial = owned;
			}
		}

		public void Dispose()
		{
			if ((Object)(object)renderer != (Object)null && (Object)(object)((Renderer)renderer).sharedMaterial == (Object)(object)owned)
			{
				((Renderer)renderer).sharedMaterial = original;
			}
			if ((Object)(object)owned != (Object)null)
			{
				Object.Destroy((Object)(object)owned);
			}
			owned = null;
			original = null;
		}
	}

	private readonly Dictionary<SpriteRenderer, Surface> surfaces = new Dictionary<SpriteRenderer, Surface>();

	private float nextDiscovery;

	private float nextVisibility;

	private bool disposed;

	public int ConvertedCount => surfaces.Count;

	public void Synchronize(Camera view, PlayerController player)
	{
		if (disposed || (Object)(object)view == (Object)null || (Object)(object)player == (Object)null)
		{
			return;
		}
		if (Time.unscaledTime >= nextVisibility)
		{
			ChunkManager instance = LazySingleton<ChunkManager>.Instance;
			if ((Object)(object)instance != (Object)null && instance.IsActive)
			{
				instance.ForceProcessVisibility();
			}
			nextVisibility = Time.unscaledTime + 0.2f;
		}
		if (Time.unscaledTime >= nextDiscovery)
		{
			Discover(view, player);
			nextDiscovery = Time.unscaledTime + 2f;
		}
		foreach (Surface value in surfaces.Values)
		{
			value.Synchronize();
		}
	}

	public void Refresh()
	{
		foreach (Surface value in surfaces.Values)
		{
			value.Dispose();
		}
		surfaces.Clear();
		nextDiscovery = 0f;
		nextVisibility = 0f;
	}

	public void Dispose()
	{
		if (!disposed)
		{
			disposed = true;
			Refresh();
		}
	}

	private void Discover(Camera view, PlayerController player)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: 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_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		float num = Mathf.Min(150f, Mathf.Max(40f, view.farClipPlane));
		float num2 = num * num;
		Transform val = (((Object)(object)player.View == (Object)null) ? null : ((Component)player.View).transform);
		SpriteRenderer[] array = Resources.FindObjectsOfTypeAll<SpriteRenderer>();
		foreach (SpriteRenderer val2 in array)
		{
			if ((Object)(object)val2 == (Object)null || surfaces.ContainsKey(val2))
			{
				continue;
			}
			Scene scene = ((Component)val2).gameObject.scene;
			if (!((Scene)(ref scene)).IsValid())
			{
				continue;
			}
			Scene scene2 = ((Component)val2).gameObject.scene;
			if (!((Scene)(ref scene2)).isLoaded || !((Component)val2).gameObject.activeInHierarchy || ((Component)val2).gameObject.layer == 5 || (Object)(object)val2.sprite == (Object)null || ((Object)(object)val != (Object)null && ((Component)val2).transform.IsChildOf(val)) || (Object)(object)((Component)val2).GetComponentInParent<Canvas>() != (Object)null)
			{
				continue;
			}
			Vector3 val3 = ((Component)val2).transform.position - ((Component)view).transform.position;
			if (!(((Vector3)(ref val3)).sqrMagnitude > num2))
			{
				Material sharedMaterial = ((Renderer)val2).sharedMaterial;
				if (!((Object)(object)sharedMaterial == (Object)null) && !((Object)(object)sharedMaterial.shader == (Object)null) && !(((Object)sharedMaterial.shader).name != "Custom/3D Sprite") && sharedMaterial.HasProperty("_ForceVertical") && !(Mathf.Abs(Vector3.Dot(((Component)val2).transform.forward, Vector3.up)) > 0.75f) && !IsGround(((Object)val2.sprite).name))
				{
					surfaces.Add(val2, new Surface(val2));
				}
			}
		}
	}

	private static bool IsGround(string name)
	{
		string text = name.ToLowerInvariant();
		if (!text.Contains("floor") && !text.Contains("ground") && !text.Contains("shadow") && !text.Contains("decal") && !text.Contains("terrain") && !text.Contains("road"))
		{
			return text.Contains("water");
		}
		return true;
	}
}