Decompiled source of PeakThingsRescueFix v0.1.3

plugins/PeakThingsRescueFix/PeakThingsRescueFix.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
using UnityEngine.SceneManagement;

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

[BepInPlugin("ehigh.PeakThingsRescueFix", "PeakThings Rescue Fix", "0.1.3")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "ehigh.PeakThingsRescueFix";

	public const string PluginName = "PeakThings Rescue Fix";

	public const string PluginVersion = "0.1.3";

	internal static Plugin Instance;

	internal static ManualLogSource Log;

	private Harmony harmony;

	private void Awake()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		harmony = new Harmony("ehigh.PeakThingsRescueFix");
		PatchByName("Evaisa.PeakThings.MonoBehaviours.TVController", "LoadTapes", typeof(TVControllerPatches), "LoadTapesPostfix");
		PatchByName("Evaisa.PeakThings.MonoBehaviours.TVController", "ExtractVideos", typeof(TVControllerPatches), "ExtractVideosPostfix");
		PatchByName("Character", "HandleDeath", typeof(CharacterDeathPatches), "CharacterDeathPrefix");
		PatchByName("Character", "Die", typeof(CharacterDeathPatches), "CharacterDeathPrefix");
		PatchByName("Character", "DieInstantly", typeof(CharacterDeathPatches), "CharacterDeathPrefix");
		PatchByName("Campfire", "Light_Rpc", typeof(CampfirePatches), "CampfireLightPostfix");
		SceneManager.sceneLoaded += OnSceneLoaded;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"PeakThings Rescue Fix loaded.");
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		if (((Scene)(ref scene)).name == "Airport")
		{
			((MonoBehaviour)this).StartCoroutine(AirportTV.EnsureAfterDelay());
			((MonoBehaviour)this).StartCoroutine(SceneCleanup.CleanupTapesForAWhile("airport scene load"));
		}
	}

	private void PatchByName(string typeName, string methodName, Type patchType, string postfixName)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		Type type = AccessTools.TypeByName(typeName);
		if (type == null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Patch skipped. Type not found: " + typeName));
			return;
		}
		MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(patchType, postfixName, (Type[])null, (Type[])null);
		if (methodInfo == null || methodInfo2 == null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Patch skipped. Missing method: " + typeName + "." + methodName));
			return;
		}
		harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched " + typeName + "." + methodName));
	}
}
internal static class TVControllerPatches
{
	public static void LoadTapesPostfix(ref IEnumerator __result)
	{
		if (__result != null)
		{
			__result = WrapTapeCoroutine(__result, "after PeakThings LoadTapes");
		}
	}

	public static void ExtractVideosPostfix(ref IEnumerator __result)
	{
		if (__result != null)
		{
			__result = WrapTapeCoroutine(__result, "after PeakThings ExtractVideos");
		}
	}

	private static IEnumerator WrapTapeCoroutine(IEnumerator original, string reason)
	{
		while (true)
		{
			bool moved;
			object current;
			try
			{
				moved = original.MoveNext();
				current = (moved ? original.Current : null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("PeakThings tape coroutine threw before cleanup: " + ex));
				throw;
			}
			if (!moved)
			{
				break;
			}
			yield return current;
		}
		yield return null;
		SceneCleanup.CleanupDuplicateTapes(reason);
	}
}
internal static class CharacterDeathPatches
{
	public static void CharacterDeathPrefix(object __instance)
	{
		CameraRecovery.RememberHeldCamera(__instance);
	}
}
internal static class CampfirePatches
{
	public static void CampfireLightPostfix(object __instance)
	{
		Component val = (Component)((__instance is Component) ? __instance : null);
		if (!((Object)(object)val == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null))
		{
			((MonoBehaviour)Plugin.Instance).StartCoroutine(CameraRecovery.MoveLooseCamerasAfterDelay(val));
		}
	}
}
internal static class AirportTV
{
	private static readonly Vector3 TvPosition = new Vector3(-15.29617f, 3.101736f, 106.5155f);

	private static readonly Quaternion TvRotation = Quaternion.Euler(0f, 0f, 0f);

	public static IEnumerator EnsureAfterDelay()
	{
		yield return (object)new WaitForSeconds(2.5f);
		if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
		{
			Plugin.Log.LogInfo((object)"Airport TV check skipped because this client is not host.");
			yield break;
		}
		GameObject existing = FindAnyTV();
		if ((Object)(object)existing != (Object)null)
		{
			MoveTV(existing);
			Plugin.Log.LogInfo((object)"Found existing PeakThings TV set and moved it to the airport fallback position.");
			yield break;
		}
		GameObject spawned = SpawnPeakThingsTV();
		if ((Object)(object)spawned != (Object)null)
		{
			MoveTV(spawned);
			Plugin.Log.LogInfo((object)("Spawned PeakThings TV set at airport fallback position: " + TvPosition));
		}
		else
		{
			Plugin.Log.LogWarning((object)"Could not spawn PeakThings TV set. Photon prefab registration may have failed.");
		}
	}

	private static GameObject FindAnyTV()
	{
		Type type = AccessTools.TypeByName("Evaisa.PeakThings.MonoBehaviours.TVController");
		if (type != null)
		{
			Object[] array = Object.FindObjectsOfType(type);
			if (array != null && array.Length > 0)
			{
				Object obj = array[0];
				Component val = (Component)(object)((obj is Component) ? obj : null);
				if (!((Object)(object)val == (Object)null))
				{
					return val.gameObject;
				}
				return null;
			}
		}
		GameObject[] array2 = Object.FindObjectsOfType<GameObject>();
		for (int i = 0; i < array2.Length; i++)
		{
			if ((Object)(object)array2[i] != (Object)null && ((Object)array2[i]).name.IndexOf("PeakThings_TVSet", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return array2[i];
			}
		}
		return null;
	}

	private static GameObject SpawnPeakThingsTV()
	{
		//IL_0005: 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)
		try
		{
			return PhotonNetwork.Instantiate("0_Items/PeakThings_TVSet", TvPosition, TvRotation, (byte)0, (object[])null);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("PhotonNetwork.Instantiate failed for PeakThings TV set: " + ex.Message));
			return SpawnThroughPeakThings("PeakThings_TVSet");
		}
	}

	private static GameObject SpawnThroughPeakThings(string prefabName)
	{
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		Type type = AccessTools.TypeByName("Evaisa.PeakThings.PeakThings");
		PropertyInfo propertyInfo = ((type == null) ? null : type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
		object obj = ((propertyInfo == null) ? null : propertyInfo.GetValue(null, null));
		MethodInfo methodInfo = ((type == null) ? null : type.GetMethod("SpawnPrefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
		{
			typeof(string),
			typeof(Vector3),
			typeof(Quaternion)
		}, null));
		if (obj == null || methodInfo == null)
		{
			return null;
		}
		object? obj2 = methodInfo.Invoke(obj, new object[3] { prefabName, TvPosition, TvRotation });
		return (GameObject)((obj2 is GameObject) ? obj2 : null);
	}

	private static void MoveTV(GameObject tv)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: 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_003c: Unknown result type (might be due to invalid IL or missing references)
		tv.transform.position = TvPosition;
		tv.transform.rotation = TvRotation;
		Rigidbody component = tv.GetComponent<Rigidbody>();
		if ((Object)(object)component != (Object)null)
		{
			component.velocity = Vector3.zero;
			component.angularVelocity = Vector3.zero;
			component.Sleep();
		}
	}
}
internal static class SceneCleanup
{
	private static float lastCleanupTime;

	public static IEnumerator CleanupTapesForAWhile(string reason)
	{
		for (int i = 0; i < 8; i++)
		{
			yield return (object)new WaitForSeconds(1f);
			CleanupDuplicateTapes(reason);
		}
	}

	public static int CleanupDuplicateTapes(string reason)
	{
		if (Time.realtimeSinceStartup - lastCleanupTime < 0.25f)
		{
			return 0;
		}
		lastCleanupTime = Time.realtimeSinceStartup;
		Type type = AccessTools.TypeByName("Evaisa.PeakThings.MonoBehaviours.VideoTape");
		if (type == null)
		{
			return 0;
		}
		Object[] array = Object.FindObjectsOfType(type);
		Dictionary<string, Component> dictionary = new Dictionary<string, Component>();
		int num = 0;
		foreach (Object obj in array)
		{
			Component val = (Component)(object)((obj is Component) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			string tapeKey = GetTapeKey(val);
			if (!string.IsNullOrEmpty(tapeKey))
			{
				if (!dictionary.TryGetValue(tapeKey, out var value) || (Object)(object)value == (Object)null)
				{
					dictionary[tapeKey] = val;
					continue;
				}
				DestroyNetworkedObject(val.gameObject);
				num++;
			}
		}
		if (num > 0)
		{
			Plugin.Log.LogInfo((object)("Removed " + num + " duplicate PeakThings tape(s), reason: " + reason));
		}
		return num;
	}

	private static string GetTapeKey(Component tape)
	{
		object fieldValue = GetFieldValue(tape, "m_flashcardEntry");
		if (fieldValue == null)
		{
			return null;
		}
		object fieldValue2 = GetFieldValue(fieldValue, "videoID");
		if (fieldValue2 != null)
		{
			string text = fieldValue2.ToString();
			if (!string.IsNullOrEmpty(text))
			{
				return "video:" + text;
			}
		}
		object fieldValue3 = GetFieldValue(fieldValue, "title");
		if (fieldValue3 != null && !string.IsNullOrEmpty(fieldValue3.ToString()))
		{
			return "title:" + fieldValue3.ToString();
		}
		return null;
	}

	private static object GetFieldValue(object instance, string fieldName)
	{
		if (instance == null)
		{
			return null;
		}
		FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName);
		if (!(fieldInfo == null))
		{
			return fieldInfo.GetValue(instance);
		}
		return null;
	}

	public static void DestroyNetworkedObject(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return;
		}
		PhotonView component = go.GetComponent<PhotonView>();
		if ((Object)(object)component != (Object)null && PhotonNetwork.InRoom)
		{
			if (PhotonNetwork.IsMasterClient || component.IsMine)
			{
				PhotonNetwork.Destroy(go);
			}
		}
		else
		{
			Object.Destroy((Object)(object)go);
		}
	}
}
internal static class CameraRecovery
{
	private static readonly Dictionary<int, GameObject> rememberedCameras = new Dictionary<int, GameObject>();

	public static void RememberHeldCamera(object character)
	{
		try
		{
			Item currentItem = GetCurrentItem(character);
			if (!((Object)(object)currentItem == (Object)null) && !((Object)(object)((Component)currentItem).gameObject == (Object)null) && IsPeakThingsCamera(((Component)currentItem).gameObject))
			{
				int stableObjectKey = GetStableObjectKey(((Component)currentItem).gameObject);
				rememberedCameras[stableObjectKey] = ((Component)currentItem).gameObject;
				Plugin.Log.LogInfo((object)("Remembered PeakThings camera for next campfire recovery: " + ((Object)((Component)currentItem).gameObject).name));
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Failed while checking held camera on death: " + ex));
		}
	}

	public static IEnumerator MoveRememberedCamerasAfterDelay(Component campfire)
	{
		yield return (object)new WaitForSeconds(1.25f);
		if ((Object)(object)campfire == (Object)null || !PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || rememberedCameras.Count == 0)
		{
			yield break;
		}
		List<int> remove = new List<int>();
		int moved = 0;
		foreach (KeyValuePair<int, GameObject> rememberedCamera in rememberedCameras)
		{
			GameObject value = rememberedCamera.Value;
			if ((Object)(object)value == (Object)null)
			{
				remove.Add(rememberedCamera.Key);
			}
			else if (!IsPeakThingsCamera(value))
			{
				remove.Add(rememberedCamera.Key);
			}
			else if (!IsHeld(value))
			{
				MoveCamera(value, campfire.transform, moved);
				remove.Add(rememberedCamera.Key);
				moved++;
			}
		}
		for (int i = 0; i < remove.Count; i++)
		{
			rememberedCameras.Remove(remove[i]);
		}
		if (moved > 0)
		{
			Plugin.Log.LogInfo((object)("Moved " + moved + " remembered PeakThings camera(s) to the lit campfire."));
		}
	}

	public static IEnumerator MoveLooseCamerasAfterDelay(Component campfire)
	{
		yield return (object)new WaitForSeconds(1.25f);
		if (!((Object)(object)campfire == (Object)null) && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
		{
			if (MoveLooseSceneCameras(campfire.transform) == 0)
			{
				Plugin.Log.LogInfo((object)"Campfire lit, but no loose PeakThings cameras were found to recover.");
			}
			if (rememberedCameras.Count > 0)
			{
				yield return MoveRememberedCamerasAfterDelay(campfire);
			}
		}
	}

	private static int MoveLooseSceneCameras(Transform campfire)
	{
		List<GameObject> list = FindPeakThingsCameras();
		int num = 0;
		for (int i = 0; i < list.Count; i++)
		{
			GameObject val = list[i];
			if (!((Object)(object)val == (Object)null) && IsPeakThingsCamera(val) && !IsInInventory(val))
			{
				MoveCamera(val, campfire, num);
				Plugin.Log.LogInfo((object)("Recovered loose PeakThings camera to lit campfire: " + ((Object)val).name));
				num++;
			}
		}
		return num;
	}

	private static List<GameObject> FindPeakThingsCameras()
	{
		List<GameObject> list = new List<GameObject>();
		Type type = AccessTools.TypeByName("Evaisa.PeakThings.MonoBehaviours.VideoCamera");
		if (type != null)
		{
			Object[] array = Object.FindObjectsOfType(type);
			foreach (Object obj in array)
			{
				Component val = (Component)(object)((obj is Component) ? obj : null);
				AddUniqueCamera(list, ((Object)(object)val == (Object)null) ? null : val.gameObject);
			}
		}
		GameObject[] array2 = Object.FindObjectsOfType<GameObject>();
		foreach (GameObject val2 in array2)
		{
			if ((Object)(object)val2 != (Object)null && ((Object)val2).name.IndexOf("PeakThings_CamcorderItem", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				AddUniqueCamera(list, val2);
			}
		}
		return list;
	}

	private static void AddUniqueCamera(List<GameObject> cameras, GameObject camera)
	{
		if ((Object)(object)camera == (Object)null)
		{
			return;
		}
		for (int i = 0; i < cameras.Count; i++)
		{
			if ((Object)(object)cameras[i] == (Object)(object)camera)
			{
				return;
			}
		}
		cameras.Add(camera);
	}

	private static Item GetCurrentItem(object character)
	{
		object memberValue = GetMemberValue(character, "data", preferProperty: false);
		if (memberValue == null)
		{
			return null;
		}
		object memberValue2 = GetMemberValue(memberValue, "currentItem", preferProperty: true);
		if (memberValue2 == null)
		{
			memberValue2 = GetMemberValue(memberValue, "_currentitem", preferProperty: false);
		}
		return (Item)((memberValue2 is Item) ? memberValue2 : null);
	}

	private static object GetMemberValue(object instance, string name, bool preferProperty)
	{
		if (instance == null)
		{
			return null;
		}
		Type type = instance.GetType();
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
		if (preferProperty)
		{
			PropertyInfo property = type.GetProperty(name, bindingAttr);
			if (property != null && property.GetIndexParameters().Length == 0)
			{
				return property.GetValue(instance, null);
			}
		}
		FieldInfo field = type.GetField(name, bindingAttr);
		if (field != null)
		{
			return field.GetValue(instance);
		}
		if (!preferProperty)
		{
			PropertyInfo property2 = type.GetProperty(name, bindingAttr);
			if (property2 != null && property2.GetIndexParameters().Length == 0)
			{
				return property2.GetValue(instance, null);
			}
		}
		return null;
	}

	private static object GetItemMemberValue(Item item, string name, bool preferProperty)
	{
		return GetMemberValue(item, name, preferProperty);
	}

	private static object GetFieldValueNoLog(object instance, string fieldName)
	{
		if (instance == null)
		{
			return null;
		}
		FieldInfo field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field == null))
		{
			return field.GetValue(instance);
		}
		return null;
	}

	private static bool IsPeakThingsCamera(GameObject go)
	{
		if ((Object)(object)go == (Object)null)
		{
			return false;
		}
		Type type = AccessTools.TypeByName("Evaisa.PeakThings.MonoBehaviours.VideoCamera");
		if (type != null && (Object)(object)go.GetComponent(type) != (Object)null)
		{
			return true;
		}
		return ((Object)go).name.IndexOf("PeakThings_CamcorderItem", StringComparison.OrdinalIgnoreCase) >= 0;
	}

	private static bool IsHeld(GameObject go)
	{
		return IsInInventory(go);
	}

	private static bool IsInInventory(GameObject go)
	{
		Item component = go.GetComponent<Item>();
		if ((Object)(object)component == (Object)null)
		{
			return false;
		}
		object obj = GetItemMemberValue(component, "holderCharacter", preferProperty: true);
		if (obj == null)
		{
			obj = GetFieldValueNoLog(component, "_holderCharacter");
		}
		if (obj == null)
		{
			obj = GetItemMemberValue(component, "trueHolderCharacter", preferProperty: true);
		}
		if (obj == null)
		{
			obj = GetFieldValueNoLog(component, "wearerCharacter");
		}
		if (obj == null)
		{
			obj = GetFieldValueNoLog(component, "overrideHolderCharacter");
		}
		return obj != null;
	}

	private static int GetStableObjectKey(GameObject go)
	{
		PhotonView component = go.GetComponent<PhotonView>();
		if ((Object)(object)component != (Object)null && component.ViewID != 0)
		{
			return component.ViewID;
		}
		return ((Object)go).GetInstanceID();
	}

	private static void MoveCamera(GameObject camera, Transform campfire, int index)
	{
		//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_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: 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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: 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_0053: 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_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: 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_006b: 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)
		//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_0091: 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_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		Vector3 right = campfire.right;
		if (((Vector3)(ref right)).sqrMagnitude < 0.01f)
		{
			right = Vector3.right;
		}
		Vector3 val = campfire.position + ((Vector3)(ref right)).normalized * (1.65f + 0.45f * (float)index);
		Vector3 forward = campfire.forward;
		Vector3 preferred = val + ((Vector3)(ref forward)).normalized * 0.4f;
		preferred = FindGroundedPosition(preferred);
		camera.transform.position = preferred;
		camera.transform.rotation = Quaternion.LookRotation((campfire.forward == Vector3.zero) ? Vector3.forward : campfire.forward, Vector3.up);
		Rigidbody component = camera.GetComponent<Rigidbody>();
		if ((Object)(object)component != (Object)null)
		{
			component.velocity = Vector3.zero;
			component.angularVelocity = Vector3.zero;
			component.WakeUp();
		}
	}

	private static Vector3 FindGroundedPosition(Vector3 preferred)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: 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)
		//IL_0010: 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_0016: 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_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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_0056: 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_0031: 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)
		Vector3 val = preferred + Vector3.up * 8f;
		RaycastHit val2 = default(RaycastHit);
		if (Physics.Raycast(val, Vector3.down, ref val2, 20f))
		{
			return ((RaycastHit)(ref val2)).point + Vector3.up * 0.85f;
		}
		return preferred + Vector3.up * 0.85f;
	}
}