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