Decompiled source of ScopophobiaSnapPatch v1.0.1

ScopoSnapPatch.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LCSoundTool;
using LethalSnapProject;
using Microsoft.CodeAnalysis;
using ScopoSnapPatch;
using ShyGuy.AI;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("ScopoSnapPatch")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ScopoSnapPatch")]
[assembly: AssemblyTitle("ScopoSnapPatch")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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;
		}
	}
}
[Serializable]
public class CustomConfig : SyncedInstance<CustomConfig>
{
	[CompilerGenerated]
	private static class <>O
	{
		public static HandleNamedMessageDelegate <0>__OnRequestSync;

		public static HandleNamedMessageDelegate <1>__OnReceiveSync;
	}

	public static ConfigEntry<bool> DebugMode;

	public static ConfigEntry<int> calmPhotoWorth;

	public static ConfigEntry<bool> calmPhotoUnique;

	public static ConfigEntry<int> triggeredPhotoWorth;

	public static ConfigEntry<bool> triggeredPhotoUnique;

	public static ConfigEntry<int> angryPhotoWorth;

	public static ConfigEntry<bool> angryPhotoUnique;

	public static ConfigEntry<float> photoAlertVolume;

	public static ConfigEntry<bool> enableEnragement;

	public static ConfigEntry<int> enrageChange;

	public CustomConfig(ConfigFile cfg)
	{
		InitInstance(this);
		calmPhotoWorth = cfg.Bind<int>("Gameplay", "Calm Photo value", 150, "How much money should a calm state SPC-096 photo be worth? Unaffected by monster multiplier config");
		calmPhotoUnique = cfg.Bind<bool>("Gameplay", "Calm Photo Unique", false, "Can you take multiple photos of SPC-096 and still get money while hes calm?");
		triggeredPhotoWorth = cfg.Bind<int>("Gameplay", "Triggered Photo value", 300, "How much money should a triggered/upset state SPC-096 photo be worth? Unaffected by monster multiplier config");
		triggeredPhotoUnique = cfg.Bind<bool>("Gameplay", "Triggered Photo Unique", true, "Can you take multiple photos of SPC-096 and still get money while hes triggered?");
		angryPhotoWorth = cfg.Bind<int>("Gameplay", "Raging Photo value", 600, "How much money should a raging/chasing SPC-096 photo be worth? Unaffected by monster multiplier config");
		angryPhotoUnique = cfg.Bind<bool>("Gameplay", "Raging Photo Unique", true, "Can you take multiple photos of SPC-096 and still get money while hes Raging?");
		enableEnragement = cfg.Bind<bool>("Enrage", "Enable Photo Enragement", true, "Should taking a photo of SPC-096 make him more angry?");
		enrageChange = cfg.Bind<int>("Enrage", "Enragement Change", 2, "How much angrier should SPC-096 get when photographed? ( remaining trigger time = trigger time / Enragement Change)");
		photoAlertVolume = cfg.Bind<float>("Audio", "Photo Alert Volume", 1.8f, "Volume multiplier for the photo alert sound effect.");
		DebugMode = cfg.Bind<bool>("Debug", "debugMode", false, "Enable more logging for troubleshooting.");
	}

	public static void RequestSync()
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		if (!SyncedInstance<CustomConfig>.IsClient)
		{
			return;
		}
		FastBufferWriter val = default(FastBufferWriter);
		((FastBufferWriter)(ref val))..ctor(SyncedInstance<CustomConfig>.IntSize, (Allocator)2, -1);
		try
		{
			SyncedInstance<CustomConfig>.MessageManager.SendNamedMessage("ScopoSnap_OnRequestConfigSync", 0uL, val, (NetworkDelivery)3);
		}
		finally
		{
			((IDisposable)(FastBufferWriter)(ref val)).Dispose();
		}
	}

	public static void OnRequestSync(ulong clientId, FastBufferReader _)
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		if (!SyncedInstance<CustomConfig>.IsHost)
		{
			return;
		}
		Plugin.Log.LogInfo((object)$"Config sync request received from client: {clientId}");
		byte[] array = SyncedInstance<CustomConfig>.SerializeToBytes(SyncedInstance<CustomConfig>.Instance);
		int num = array.Length;
		FastBufferWriter val = default(FastBufferWriter);
		((FastBufferWriter)(ref val))..ctor(num + SyncedInstance<CustomConfig>.IntSize, (Allocator)2, -1);
		try
		{
			((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
			((FastBufferWriter)(ref val)).WriteBytesSafe(array, -1, 0);
			SyncedInstance<CustomConfig>.MessageManager.SendNamedMessage("ScopoSnap_OnReceiveConfigSync", clientId, val, (NetworkDelivery)3);
		}
		catch (Exception arg)
		{
			Plugin.Log.LogInfo((object)$"Error occurred syncing config with client: {clientId}\n{arg}");
		}
		finally
		{
			((IDisposable)(FastBufferWriter)(ref val)).Dispose();
		}
	}

	public static void OnReceiveSync(ulong _, FastBufferReader reader)
	{
		//IL_002d: 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)
		if (!((FastBufferReader)(ref reader)).TryBeginRead(SyncedInstance<CustomConfig>.IntSize))
		{
			Plugin.Log.LogError((object)"Config sync error: Could not begin reading buffer.");
			return;
		}
		int num = default(int);
		((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
		if (!((FastBufferReader)(ref reader)).TryBeginRead(num))
		{
			Plugin.Log.LogError((object)"Config sync error: Host could not sync.");
			return;
		}
		byte[] data = new byte[num];
		((FastBufferReader)(ref reader)).ReadBytesSafe(ref data, num, 0);
		SyncedInstance<CustomConfig>.SyncInstance(data);
		Plugin.Log.LogInfo((object)"Successfully synced config with host.");
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(GameNetworkManager), "SteamMatchmaking_OnLobbyMemberJoined")]
	public static void InitializeLocalPlayer()
	{
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		Plugin.Log.LogInfo((object)"Trying to sync config files");
		if (SyncedInstance<CustomConfig>.IsHost)
		{
			CustomMessagingManager messageManager = SyncedInstance<CustomConfig>.MessageManager;
			object obj = <>O.<0>__OnRequestSync;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = OnRequestSync;
				<>O.<0>__OnRequestSync = val;
				obj = (object)val;
			}
			messageManager.RegisterNamedMessageHandler("ScopoSnap_OnRequestConfigSync", (HandleNamedMessageDelegate)obj);
			SyncedInstance<CustomConfig>.Synced = true;
			return;
		}
		SyncedInstance<CustomConfig>.Synced = false;
		CustomMessagingManager messageManager2 = SyncedInstance<CustomConfig>.MessageManager;
		object obj2 = <>O.<1>__OnReceiveSync;
		if (obj2 == null)
		{
			HandleNamedMessageDelegate val2 = OnReceiveSync;
			<>O.<1>__OnReceiveSync = val2;
			obj2 = (object)val2;
		}
		messageManager2.RegisterNamedMessageHandler("ScopoSnap_OnReceiveConfigSync", (HandleNamedMessageDelegate)obj2);
		RequestSync();
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(GameNetworkManager), "StartDisconnect")]
	public static void PlayerLeave()
	{
		Plugin.Log.LogInfo((object)"Trying to reset config file");
		SyncedInstance<CustomConfig>.RevertSync();
	}
}
[Serializable]
public class SyncedInstance<T>
{
	[NonSerialized]
	protected static int IntSize = 4;

	internal static CustomMessagingManager MessageManager => NetworkManager.Singleton.CustomMessagingManager;

	internal static bool IsClient => NetworkManager.Singleton.IsClient;

	internal static bool IsHost => NetworkManager.Singleton.IsHost;

	public static T Default { get; private set; }

	public static T Instance { get; private set; }

	public static bool Synced { get; internal set; }

	protected void InitInstance(T instance)
	{
		Default = instance;
		Instance = instance;
		IntSize = 4;
	}

	internal static void SyncInstance(byte[] data)
	{
		Instance = DeserializeFromBytes(data);
		Synced = true;
	}

	internal static void RevertSync()
	{
		Instance = Default;
		Synced = false;
	}

	public static byte[] SerializeToBytes(T val)
	{
		BinaryFormatter binaryFormatter = new BinaryFormatter();
		using MemoryStream memoryStream = new MemoryStream();
		try
		{
			binaryFormatter.Serialize(memoryStream, val);
			return memoryStream.ToArray();
		}
		catch (Exception arg)
		{
			Plugin.MyLogger.LogError((object)$"Error serializing instance: {arg}");
			return null;
		}
	}

	public static T DeserializeFromBytes(byte[] data)
	{
		BinaryFormatter binaryFormatter = new BinaryFormatter();
		using MemoryStream serializationStream = new MemoryStream(data);
		try
		{
			return (T)binaryFormatter.Deserialize(serializationStream);
		}
		catch (Exception arg)
		{
			Plugin.MyLogger.LogError((object)$"Error deserializing instance: {arg}");
			return default(T);
		}
	}
}
internal static class LCMPluginInfo
{
	public const string PLUGIN_GUID = "ScopoSnapPatch";

	public const string PLUGIN_NAME = "ScopoSnapPatch";

	public const string PLUGIN_VERSION = "1.0.0";
}
namespace ScopoSnapPatch
{
	[BepInPlugin("gulfbones.scoposnappatch", "ScopoSnap Patch", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "gulfbones.scoposnappatch";

		public const string NAME = "ScopoSnap Patch";

		public const string VER = "1.0.0";

		internal static ManualLogSource Log = null;

		private readonly Harmony _harmony = new Harmony("gulfbones.scoposnappatch");

		private static Plugin _instance;

		public static bool DebugMode = true;

		internal static AudioClip photoAlertSFX;

		public static CustomConfig MyConfig { get; internal set; }

		private void Awake()
		{
			if ((Object)(object)_instance == (Object)null)
			{
				_instance = this;
			}
			MyConfig = new CustomConfig(((BaseUnityPlugin)this).Config);
			DebugMode = CustomConfig.DebugMode.Value;
			Log = ((BaseUnityPlugin)this).Logger;
			if (DebugMode)
			{
				Log.LogInfo((object)"Debug logging is enabled for this plugin.");
			}
			photoAlertSFX = SoundTool.GetAudioClip(Path.GetDirectoryName(((BaseUnityPlugin)_instance).Info.Location), "096_Angered.ogg");
			if ((Object)(object)photoAlertSFX == (Object)null)
			{
				Log.LogError((object)"Failed to load sound effect 096_Angered.ogg from embedded resources.");
			}
			else
			{
				Log.LogInfo((object)"Successfully loaded sound effect 096_Angered.ogg from embedded resources.");
			}
			SnapReactPatch.Apply(_harmony);
			Log.LogInfo((object)"Plugin ScopoSnap Patch version 1.0.0 is loaded!");
		}
	}
	internal class SnapReactPatch
	{
		public static Dictionary<string, float> scopoCustomValues = new Dictionary<string, float>
		{
			{
				"shyguy_calm",
				CustomConfig.calmPhotoWorth.Value
			},
			{
				"shyguy_triggered",
				CustomConfig.triggeredPhotoWorth.Value
			},
			{
				"shyguy_angry",
				CustomConfig.angryPhotoWorth.Value
			}
		};

		public static void Apply(Harmony harmony)
		{
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Expected O, but got Unknown
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("LethalSnapProject.Behaviour.MonsterReact");
			MethodInfo methodInfo = AccessTools.Method(type, "ReactToFlash", (Type[])null, (Type[])null);
			Type type2 = AccessTools.TypeByName("LethalSnapProject.Behaviour.PictureHelper");
			MethodInfo methodInfo2 = AccessTools.Method(type2, "ComputePictureValue", (Type[])null, (Type[])null);
			Type type3 = AccessTools.TypeByName("LethalSnapProject.Behaviour.PictureHelper");
			MethodInfo methodInfo3 = AccessTools.Method(type3, "GetMonsterScore", (Type[])null, (Type[])null);
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type2))
			{
				Plugin.Log.LogInfo((object)("Found method: " + declaredMethod.Name));
			}
			if (type == null || methodInfo == null)
			{
				Plugin.Log.LogError((object)"Failed to find  MonsterReact.ReactToFlash()  for patching.");
			}
			else
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("type: " + type?.ToString() + "| Method: " + methodInfo));
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(SnapReactPatch), "SnapAngerPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (type2 == null || methodInfo2 == null)
			{
				Plugin.Log.LogError((object)"Failed to find PictureHelper.ComputePictureValue() method for patching.");
			}
			else
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogInfo((object)("type: " + type2?.ToString() + "| Method: " + methodInfo2));
				}
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(SnapReactPatch), "SnapValuePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (type3 == null || methodInfo3 == null)
			{
				Plugin.Log.LogError((object)"Failed to find PictureHelper.GetMonsterScore() method for patching.");
				return;
			}
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("type: " + type3?.ToString() + "| Method: " + methodInfo3));
			}
			harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(SnapReactPatch), "MonsterScorePatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void SnapAngerPatch(ref PlayerControllerB owner, ref EnemyAI enemy)
		{
			PlayerControllerB val = owner;
			EnemyAI val2 = enemy;
			string text = val2.enemyType.enemyName.ToLower();
			if (!(text == "shy guy") || !CustomConfig.enableEnragement.Value)
			{
				return;
			}
			ShyGuyAI val3 = (ShyGuyAI)(object)((val2 is ShyGuyAI) ? val2 : null);
			if ((Object)(object)val3 == (Object)null)
			{
				return;
			}
			if (((EnemyAI)val3).currentBehaviourStateIndex != 1)
			{
				if (Plugin.DebugMode)
				{
					Plugin.Log.LogWarning((object)("Shy guy was in state " + ((EnemyAI)val3).currentBehaviourStateIndex + " therefore no timer change"));
				}
				return;
			}
			Plugin.Log.LogInfo((object)"Shy guy got Angrier!");
			FieldInfo fieldInfo = AccessTools.Field(typeof(ShyGuyAI), "triggerTime");
			float num = (float)fieldInfo.GetValue(val3);
			num /= (float)CustomConfig.enrageChange.Value;
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("Shyguy timer reduced to: " + num));
			}
			fieldInfo.SetValue(val3, num);
			val3.AddTargetToList((int)owner.actualClientId, false);
			if ((Object)(object)Plugin.photoAlertSFX == (Object)null)
			{
				Plugin.Log.LogError((object)"Photo alert SFX is null!");
				return;
			}
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)"Playing photo alert SFX");
			}
			val3.farAudio.PlayOneShot(Plugin.photoAlertSFX, CustomConfig.photoAlertVolume.Value);
		}

		public static void SnapValuePatch(ref List<VisibleEntity> entities, ref bool isUnique)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < entities.Count; i++)
			{
				if (!(entities[i].name.ToLower() == "shy guy"))
				{
					continue;
				}
				string name = "shy guy";
				ShyGuyAI[] array = Object.FindObjectsOfType<ShyGuyAI>(false);
				if (((EnemyAI)array[0]).currentBehaviourStateIndex == 0)
				{
					name = "shyguy_calm";
					if (CustomConfig.calmPhotoUnique.Value)
					{
						isUnique = true;
					}
				}
				if (((EnemyAI)array[0]).currentBehaviourStateIndex == 1)
				{
					name = "shyguy_triggered";
					if (CustomConfig.triggeredPhotoUnique.Value)
					{
						isUnique = true;
					}
				}
				if (((EnemyAI)array[0]).currentBehaviourStateIndex == 2)
				{
					name = "shyguy_angry";
					if (CustomConfig.angryPhotoUnique.Value)
					{
						isUnique = true;
					}
				}
				VisibleEntity val = default(VisibleEntity);
				val.name = name;
				val.isPlayer = false;
				val.isOutside = entities[i].isOutside;
				val.networkID = entities[i].networkID;
				VisibleEntity value = val;
				entities[i] = value;
			}
		}

		public static bool MonsterScorePatch(ref string monsterName, ref float __result)
		{
			string key = monsterName.ToLower();
			if (scopoCustomValues.TryGetValue(key, out var value))
			{
				__result = value;
				Plugin.Log.LogInfo((object)$"SCP-096 '{monsterName}' scored with value {__result}");
				return false;
			}
			if (Plugin.DebugMode)
			{
				Plugin.Log.LogInfo((object)("didnt find NOTHING! Monster name was: " + monsterName));
			}
			return true;
		}
	}
}