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;
}
}