#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using Backrooms;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using GameNetcodeStuff;
using GroanTubeScrap;
using HarmonyLib;
using JetBrains.Annotations;
using LCSoundTool;
using LethalLib.Modules;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TestAccount666.RealBackroomsPatch")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Backrooms Patch, but real")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0")]
[assembly: AssemblyProduct("RealBackroomsPatch")]
[assembly: AssemblyTitle("TestAccount666.RealBackroomsPatch")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace RealBackroomsPatch
{
public class BackroomsConfig
{
private readonly ConfigFile _configFile;
public ConfigEntry<DropHeldItemsMode> DropHeldItemsMode { get; private set; }
public ConfigEntry<bool> ShouldPreventDamageTeleport { get; private set; }
public ConfigEntry<bool> ShouldPreventDeathTeleport { get; private set; }
public ConfigEntry<bool> ShouldPreventNegativeDamageTeleport { get; private set; }
[CanBeNull]
public ConfigEntry<bool> ShouldSpawnDeadBody { get; private set; } = null;
public ConfigEntry<bool> ShouldTeleportAnnoyingPeople { get; private set; }
[CanBeNull]
public ConfigEntry<bool> ShouldTeleportToAndReplaceDeadBody { get; private set; } = null;
public ConfigEntry<int> TeleportAnnoyingPeopleChance { get; private set; }
public ConfigEntry<int> TeleportLethalDamageChance { get; private set; }
public ConfigEntry<int> TeleportNonLethalDamageChance { get; private set; }
public ConfigEntry<string> PreventBackroomsTeleportEnemies { get; private set; }
public ConfigEntry<int> LightFlickerSmoothing { get; private set; }
public ConfigEntry<float> LightFlickerMinIntensity { get; private set; }
public ConfigEntry<float> LightFlickerMaxIntensity { get; private set; }
public ConfigEntry<bool> PlayMusic { get; private set; }
public BackroomsConfig(string guid, ConfigFile configFile)
{
_configFile = configFile;
HandleConfig();
RemoveOrphans();
Plugin.InfoLog("Printing Config:");
Plugin.InfoLog($"DropHeldItemsMode: {DropHeldItemsMode.Value}");
Plugin.InfoLog($"ShouldPreventDamageTeleport: {ShouldPreventDamageTeleport.Value}");
Plugin.InfoLog($"ShouldPreventDeathTeleport: {ShouldPreventDeathTeleport.Value}");
Plugin.InfoLog($"ShouldPreventNegativeDamageTeleport: {ShouldPreventNegativeDamageTeleport.Value}");
Plugin.InfoLog($"ShouldTeleportAnnoyingPeople: {ShouldTeleportAnnoyingPeople.Value}");
Plugin.InfoLog($"TeleportAnnoyingPeopleChance: {TeleportAnnoyingPeopleChance.Value}");
Plugin.InfoLog($"TeleportLethalDamageChance: {TeleportLethalDamageChance.Value}");
Plugin.InfoLog($"TeleportNonLethalDamageChance: {TeleportNonLethalDamageChance.Value}");
Plugin.InfoLog("PreventBackroomsTeleportEnemies: " + PreventBackroomsTeleportEnemies.Value);
}
private void HandleConfig()
{
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Expected O, but got Unknown
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Expected O, but got Unknown
//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Expected O, but got Unknown
Plugin.InfoLog("Handling Config!");
ShouldPreventDamageTeleport = _configFile.Bind<bool>("Teleport", "Prevent damage teleport", true, "If true, will prevent the backrooms mod from teleporting players that received damage");
ShouldPreventDeathTeleport = _configFile.Bind<bool>("Teleport", "Prevent death teleport", false, "If true, will prevent the backrooms mod from teleporting players that received deadly damage");
ShouldPreventNegativeDamageTeleport = _configFile.Bind<bool>("Teleport", "Prevent negative damage teleport", false, "If true, will prevent the backrooms mod from teleporting players that received negative damage (Aka healing)");
DropHeldItemsMode = _configFile.Bind<DropHeldItemsMode>("Teleport", "Drop held items on teleport", RealBackroomsPatch.DropHeldItemsMode.DropNothing, "When do you want items to be dropped when teleported into the backrooms?");
PreventBackroomsTeleportEnemies = _configFile.Bind<string>("Teleport", "Prevent backrooms when attacked by enemies", "Flowerman, MaskedPlayer", "A list of enemies that will not allow you to spawn in the backrooms, if attacked by them (Needs internal name. Example: Flowerman, Jester, ...)");
TeleportLethalDamageChance = _configFile.Bind<int>("Chances", "Teleport lethal damage chance", 1, "The chance that a person will get teleported into the backrooms with lethal damage (Requires \"Prevent death teleport\" set to \"false\")");
TeleportNonLethalDamageChance = _configFile.Bind<int>("Chances", "Teleport non-lethal damage chance", 3, "The chance that a person will get teleported into the backrooms with non-lethal damage (Requires \"Prevent damage teleport\" set to \"false\")");
ShouldTeleportAnnoyingPeople = _configFile.Bind<bool>("Extra", "Teleport annoying people", false, "If true, will teleport annoying people (e.g. People using horns)");
TeleportAnnoyingPeopleChance = _configFile.Bind<int>("Extra", "Teleport annoying people chance", 10, "The chance that annoying people can get teleported");
LightFlickerSmoothing = _configFile.Bind<int>("Light Flickering", "Smoothing", 25, new ConfigDescription("How much to smooth out the randomness; lower values = sparks, higher = lantern", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
LightFlickerMinIntensity = _configFile.Bind<float>("Light Flickering", "Min intensity", 0.2f, new ConfigDescription("Minimum random light intensity", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
LightFlickerMaxIntensity = _configFile.Bind<float>("Light Flickering", "Max intensity", 1.5f, new ConfigDescription("Maximum random light intensity", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
PlayMusic = _configFile.Bind<bool>("Music", "Play Music", true, "If true, plays music in the backrooms");
Plugin.InfoLog("Handled Config!");
}
private void RemoveOrphans()
{
PropertyInfo property = ((object)_configFile).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);
if (!(property == null))
{
Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(_configFile, null);
dictionary.Clear();
_configFile.Save();
}
}
}
[HarmonyPatch(typeof(StartOfRound))]
public class DebugPatch
{
[HarmonyPatch("Start")]
[HarmonyPostfix]
public static void PrintConfigOnStart()
{
Plugin.InfoLog("Printing Config:");
Plugin.InfoLog($"DropHeldItemsMode: {Plugin.backroomsConfig.DropHeldItemsMode.Value}");
Plugin.InfoLog($"ShouldPreventDamageTeleport: {Plugin.backroomsConfig.ShouldPreventDamageTeleport.Value}");
Plugin.InfoLog($"ShouldPreventDeathTeleport: {Plugin.backroomsConfig.ShouldPreventDeathTeleport.Value}");
Plugin.InfoLog($"ShouldPreventNegativeDamageTeleport: {Plugin.backroomsConfig.ShouldPreventNegativeDamageTeleport.Value}");
Plugin.InfoLog($"ShouldTeleportAnnoyingPeople: {Plugin.backroomsConfig.ShouldTeleportAnnoyingPeople.Value}");
Plugin.InfoLog($"TeleportAnnoyingPeopleChance: {Plugin.backroomsConfig.TeleportAnnoyingPeopleChance.Value}");
Plugin.InfoLog($"TeleportLethalDamageChance: {Plugin.backroomsConfig.TeleportLethalDamageChance.Value}");
Plugin.InfoLog($"TeleportNonLethalDamageChance: {Plugin.backroomsConfig.TeleportNonLethalDamageChance.Value}");
Plugin.InfoLog("PreventBackroomsTeleportEnemies: " + Plugin.backroomsConfig.PreventBackroomsTeleportEnemies.Value);
}
}
public static class DependencyChecker
{
public static bool IsGroanTubeModInstalled()
{
return Chainloader.PluginInfos.Values.Any((PluginInfo metadata) => metadata.Metadata.GUID.Equals("Kittenji.GroanTubeScrap"));
}
public static bool IsSoundToolsModInstalled()
{
return Chainloader.PluginInfos.Values.Any((PluginInfo metadata) => metadata.Metadata.GUID.Equals("LCSoundTool"));
}
}
[DataContract]
public enum DropHeldItemsMode
{
[EnumMember]
DropNothing,
[EnumMember]
DropAll,
[EnumMember]
DropAllOnDeath,
[EnumMember]
DropAllOnAnnoying,
[EnumMember]
DropAllOnAnnoyingAndDeath
}
[HarmonyPatch]
public class GroanTubePatch
{
public static MethodBase TargetMethod()
{
Type type2 = AccessTools.GetTypesFromAssembly(typeof(Loader).Assembly).FirstOrDefault((Type type1) => type1.Name.Contains("GroanTubeItem"));
return (type2 == null) ? null : AccessTools.FirstMethod(type2, (Func<MethodInfo, bool>)((MethodInfo method) => method.Name.Contains("ItemActivate")));
}
public static void Prefix(NoisemakerProp __instance)
{
if (!((GrabbableObject)__instance).isHeld)
{
Plugin.WarningLog("Groan Tube not held!");
}
else
{
Patches.TeleportForAnnoyingPeople(((GrabbableObject)__instance).playerHeldBy);
}
}
}
[RequireComponent(typeof(SphereCollider))]
public class FixedKillBox : MonoBehaviour
{
public void OnTriggerEnter(Collider other)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
PlayerControllerB component = ((Component)other).gameObject.GetComponent<PlayerControllerB>();
if (!((Object)(object)component == (Object)null))
{
component.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3));
}
}
}
[HarmonyPatch(typeof(LightFlickerEffect))]
public static class LightFlickerEffectPatch
{
[HarmonyPatch("Start")]
[HarmonyPostfix]
private static void StartPostfix(LightFlickerEffect __instance)
{
__instance.smoothing = Plugin.backroomsConfig.LightFlickerSmoothing.Value;
__instance.minIntensity = Plugin.backroomsConfig.LightFlickerMinIntensity.Value;
__instance.maxIntensity = Plugin.backroomsConfig.LightFlickerMaxIntensity.Value;
}
}
public class MusicPlayer : MonoBehaviour
{
private const int MUSIC_COOLDOWN = 1000;
private const float VOLUME_DECREASE_STEP = 0.05f;
private readonly Random _random = new Random();
[CanBeNull]
private AudioSource _audioSource;
private int? _instanceId;
private long _nextTimePlaying = UnixTime.GetCurrentTime() + 1000;
private bool _shouldStop;
private void Update()
{
if (_shouldStop)
{
return;
}
long currentTime = UnixTime.GetCurrentTime();
if (_nextTimePlaying <= currentTime)
{
int? instanceId = _instanceId;
if (!instanceId.HasValue || Object.FindObjectFromInstanceID(_instanceId.Value) == null)
{
PlayMusic();
}
}
}
private void PlayMusic()
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
long currentTime = UnixTime.GetCurrentTime();
int num = _random.Next(0, Plugin.MusicSounds.Count);
AudioClip val = Plugin.MusicSounds[num];
Plugin.DebugLog($"Playing clip '{((Object)val).name}' ({num})");
GameObject val2 = new GameObject("TemporaryMusicAudio");
_instanceId = ((Object)val2).GetInstanceID();
_audioSource = val2.AddComponent<AudioSource>();
Debug.Assert((Object)(object)_audioSource != (Object)null, "_audioSource != null");
_audioSource.clip = val;
_audioSource.volume = 0.5f;
_audioSource.Play();
_nextTimePlaying = (long)((float)(currentTime + 1000) + val.length * 1000f);
Object.Destroy((Object)(object)val2, val.length);
}
public void Stop()
{
_shouldStop = true;
((MonoBehaviour)this).StartCoroutine(FadeOutMusic());
}
private void TerminateMusic()
{
if (_instanceId.HasValue)
{
Object val = Object.FindObjectFromInstanceID(_instanceId.Value);
if (val == (Object)null)
{
return;
}
Object.Destroy(val);
}
Object.Destroy((Object)(object)this);
}
private IEnumerator FadeOutMusic()
{
if ((Object)(object)_audioSource == (Object)null)
{
TerminateMusic();
yield break;
}
if (!_audioSource.isPlaying)
{
TerminateMusic();
yield break;
}
AudioSource audioSource = _audioSource;
audioSource.volume -= 0.05f * Time.deltaTime;
if (_audioSource.volume <= 0f)
{
TerminateMusic();
yield break;
}
yield return (object)new WaitForEndOfFrame();
yield return FadeOutMusic();
}
}
[HarmonyPatch]
public static class Patches
{
private static readonly List<ulong> _ImmortalPlayers = new List<ulong>();
private static readonly int _BiohazardDamage = Animator.StringToHash("biohazardDamage");
public static void UnpatchDamagePlayerMethod([NotNull] Harmony harmony)
{
if (!Unpatch<PlayerControllerB>(harmony, "DamagePlayer", "BeforeDamage"))
{
Plugin.ErrorLog("Failed to unpatch DamagePlayer!");
}
}
public static void UnpatchKillPlayerMethod([NotNull] Harmony harmony)
{
if (!Unpatch<KillLocalPlayer>(harmony, "KillPlayer", "BeforeKilling"))
{
Plugin.ErrorLog("Failed to unpatch KillPlayer!");
}
}
[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")]
[HarmonyPrefix]
public static bool TeleportOnDamage(int damageNumber, CauseOfDeath causeOfDeath, Vector3 force, int deathAnimation, PlayerControllerB __instance)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
bool lethalDamage = __instance.health - damageNumber <= 0;
bool negativeDamage = damageNumber <= 0;
Plugin.InfoLog("TeleportOnDamage!");
if (!MeetRequirementsForBackrooms(__instance, lethalDamage, negativeDamage))
{
return true;
}
RpcCollection.Instance.TeleportPlayerToBackroomsServerRpc((int)__instance.playerClientId, spawnBody: false, force, causeOfDeath, deathAnimation, lethalDamage, negativeDamage);
return false;
}
[HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")]
[HarmonyPrefix]
public static bool TeleportOnKill(Vector3 bodyVelocity, bool spawnBody, CauseOfDeath causeOfDeath, int deathAnimation, Vector3 positionOffset, PlayerControllerB __instance)
{
//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)
Plugin.InfoLog("TeleportOnKill!");
if (Plugin.backroomsConfig.ShouldPreventDeathTeleport.Value)
{
return true;
}
if (!MeetRequirementsForBackrooms(__instance))
{
return true;
}
RpcCollection.Instance.TeleportPlayerToBackroomsServerRpc((int)__instance.playerClientId, spawnBody, bodyVelocity, causeOfDeath, deathAnimation);
return false;
}
[HarmonyPatch(typeof(PlayerControllerB), "AllowPlayerDeath")]
[HarmonyPrefix]
public static bool PreventPlayerDeath(ref bool __result, PlayerControllerB __instance)
{
if (Plugin.backroomsConfig.ShouldPreventDeathTeleport.Value)
{
return true;
}
if (!_ImmortalPlayers.Contains(__instance.playerSteamId))
{
return true;
}
__result = false;
return false;
}
[HarmonyPatch(typeof(NoisemakerProp), "ItemActivate")]
[HarmonyPrefix]
public static void TeleportForAnnoyingPeople(PlayerControllerB ___playerHeldBy)
{
//IL_003a: 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)
if (Plugin.backroomsConfig.ShouldTeleportAnnoyingPeople.Value && MeetRequirementsForBackrooms(___playerHeldBy, lethalDamage: false, negativeDamage: false, annoying: true))
{
RpcCollection.Instance.TeleportPlayerToBackroomsServerRpc((int)___playerHeldBy.playerClientId, spawnBody: false, default(Vector3), (CauseOfDeath)0, 0, lethalDamage: false, negativeDamage: false, annoying: true);
}
}
[HarmonyPatch(typeof(Backrooms), "TeleportOutOfBackroomsClientRpc")]
[HarmonyPostfix]
public static void RestoreVanillaSounds(int client)
{
if (client == (int)StartOfRound.Instance.localPlayerController.playerClientId)
{
if (Plugin.enableSoundReplace)
{
SoundToolsWrapper.RestoreAudioClip("WoodStep1");
SoundToolsWrapper.RestoreAudioClip("WoodStep2");
SoundToolsWrapper.RestoreAudioClip("WoodStep3");
SoundToolsWrapper.RestoreAudioClip("WoodStep4");
}
MusicPlayer component = ((Component)StartOfRound.Instance.localPlayerController).GetComponent<MusicPlayer>();
if (!((Object)(object)component == (Object)null))
{
component.Stop();
}
}
}
[HarmonyPatch(typeof(Backrooms), "TeleportOutOfBackroomsClientRpc")]
[HarmonyPostfix]
public static void TeleportToAndReplaceDeadBody(int client, Backrooms ___Instance)
{
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Invalid comparison between Unknown and I4
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: 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_00f3: 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_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.backroomsConfig.ShouldTeleportToAndReplaceDeadBody == null)
{
return;
}
Debug.Assert(Plugin.backroomsConfig.ShouldTeleportToAndReplaceDeadBody != null, "Plugin.BackroomsConfig.ShouldTeleportToAndReplaceDeadBody != null");
if (!Plugin.backroomsConfig.ShouldTeleportToAndReplaceDeadBody.Value)
{
return;
}
PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[client];
DeadBodyInfo deadBody = val.deadBody;
if (!((Object)(object)deadBody == (Object)null) && !deadBody.deactivated && (deadBody.grabBodyObject.isInShipRoom || !deadBody.grabBodyObject.isInFactory || (int)deadBody.causeOfDeath != 2))
{
Vector3 itemFloorPosition = deadBody.grabBodyObject.GetItemFloorPosition(default(Vector3));
bool isInFactory = deadBody.grabBodyObject.isInFactory;
bool isInShipRoom = deadBody.grabBodyObject.isInShipRoom;
bool isInElevator = deadBody.grabBodyObject.isInElevator;
Vector3 spawnPosition = deadBody.spawnPosition;
spawnPosition.x += Vector3.down.x * 200f;
spawnPosition.y += Vector3.down.y * 200f;
spawnPosition.z += Vector3.down.z * 200f;
deadBody.SetRagdollPositionSafely(spawnPosition, true);
if (((NetworkBehaviour)Backrooms.Instance).IsHost || ((NetworkBehaviour)Backrooms.Instance).IsServer)
{
val.SyncBodyPositionWithClients();
((NetworkBehaviour)deadBody.grabBodyObject).NetworkObject.Despawn(true);
}
val.deadBody = null;
val.TeleportPlayer(itemFloorPosition, false, 0f, false, true);
val.isInsideFactory = isInFactory;
val.isInHangarShipRoom = isInShipRoom;
val.isInElevator = isInElevator;
}
}
private static bool CompareMethodInfoAndMethodBase(MethodInfo methodInfo, MethodBase methodBase)
{
if (methodInfo == null)
{
return false;
}
if (methodBase == null)
{
return false;
}
if (methodInfo.DeclaringType == null)
{
return false;
}
if (methodBase.DeclaringType == null)
{
return false;
}
bool flag = methodInfo.Name == methodBase.Name;
Debug.Assert(methodInfo.DeclaringType.FullName != null, "methodInfo.DeclaringType.FullName != null");
bool flag2 = methodInfo.DeclaringType.FullName.Equals(methodBase.DeclaringType.FullName);
return flag && flag2;
}
private static bool Unpatch<T>([NotNull] Harmony harmony, [NotNull] string originalMethodName, [NotNull] string backroomsMethodName)
{
MethodInfo methodInfo = typeof(T).GetMethods().FirstOrDefault((MethodInfo method) => method.Name.Equals(originalMethodName));
MethodInfo method2 = typeof(Hook).GetMethod(backroomsMethodName, BindingFlags.Static | BindingFlags.NonPublic);
foreach (MethodBase allPatchedMethod in Harmony.GetAllPatchedMethods())
{
if (!CompareMethodInfoAndMethodBase(methodInfo, allPatchedMethod))
{
continue;
}
Patches patchInfo = Harmony.GetPatchInfo(allPatchedMethod);
if (patchInfo == null)
{
Plugin.ErrorLog("Failed to retrieve patch information for method: " + allPatchedMethod.Name);
continue;
}
foreach (Patch prefix in patchInfo.Prefixes)
{
MethodInfo method3 = prefix.GetMethod((MethodBase)method2);
if (!CompareMethodInfoAndMethodBase(method2, method3))
{
continue;
}
harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)1, prefix.owner);
Plugin.InfoLog("Unpatched " + originalMethodName + " method!");
return true;
}
}
Plugin.ErrorLog("Target method not found: " + originalMethodName);
return false;
}
private static void DisablePlayerDeath(int secondsFor, PlayerControllerB player)
{
_ImmortalPlayers.Add(player.playerSteamId);
Timer timer = null;
timer = new Timer(delegate
{
_ImmortalPlayers.Remove(player.playerSteamId);
timer?.Dispose();
}, null, secondsFor * 1000, -1);
}
internal static void SpawnDeadBody(PlayerControllerB player, Vector3 bodyVelocity, CauseOfDeath causeOfDeath, int deathAnimation, EnemyAI enemyAI, bool isServer = true)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Expected I4, but got Unknown
string text = $"PositionObject-{player.playerClientId}-{SystemClock.ToUnixTimeMilliseconds(SystemClock.now)}";
GameObject val = new GameObject(text);
Transform transform = val.transform;
transform.position = player.oldPlayerPosition;
transform.rotation = player.thisPlayerBody.rotation;
if (isServer)
{
GameObject val2 = Object.Instantiate<GameObject>(StartOfRound.Instance.ragdollGrabbableObjectPrefab, player.playersManager.propsContainer);
val2.GetComponent<NetworkObject>().Spawn(false);
val2.GetComponent<RagdollGrabbableObject>().bodyID.Value = (int)player.playerClientId;
}
player.SpawnDeadBody((int)player.playerClientId, bodyVelocity, (int)causeOfDeath, player, deathAnimation, transform, default(Vector3));
player.deadBody.canBeGrabbedBackByPlayers = true;
if (isServer)
{
player.SyncBodyPositionWithClients();
}
if (!((Object)(object)enemyAI == (Object)null))
{
FlowermanAI val3 = (FlowermanAI)(object)((enemyAI is FlowermanAI) ? enemyAI : null);
if (val3 != null)
{
((EnemyAI)val3).inSpecialAnimationWithPlayer = player;
val3.FinishKillAnimation(true);
}
}
}
private static void EnemyFixes(EnemyAI enemyAI)
{
FlowermanAI val = (FlowermanAI)(object)((enemyAI is FlowermanAI) ? enemyAI : null);
if (val == null)
{
MaskedPlayerEnemy val2 = (MaskedPlayerEnemy)(object)((enemyAI is MaskedPlayerEnemy) ? enemyAI : null);
if (val2 != null)
{
if ((Object)(object)((EnemyAI)val2).inSpecialAnimationWithPlayer == (Object)(object)GameNetworkManager.Instance.localPlayerController)
{
HUDManager.Instance.HUDAnimator.SetBool(_BiohazardDamage, false);
HUDManager.Instance.HideHUD(true);
HUDManager.Instance.HideHUD(false);
}
val2.FinishKillAnimation(false);
((EnemyAI)val2).inSpecialAnimationWithPlayer = null;
}
}
else
{
val.FinishKillAnimation(false);
((EnemyAI)val).inSpecialAnimation = false;
}
}
private static bool MeetRequirementsForBackrooms(PlayerControllerB player, bool lethalDamage = true, bool negativeDamage = false, bool annoying = false)
{
if ((Object)(object)player == (Object)null)
{
return false;
}
Plugin.InfoLog("Player exists!");
if (player.isPlayerDead || !player.AllowPlayerDeath() || ((Component)player).GetComponent<BackroomsHelper>().HasBeenInTheBackrooms)
{
return false;
}
Plugin.InfoLog("Passed checks!");
if (negativeDamage && Plugin.backroomsConfig.ShouldPreventNegativeDamageTeleport.Value)
{
return false;
}
Plugin.InfoLog("Negative damage check passed!");
Plugin.InfoLog("Prevent Death Teleport: " + Plugin.backroomsConfig.ShouldPreventDeathTeleport.Value);
Plugin.InfoLog("Prevent Damage Teleport: " + Plugin.backroomsConfig.ShouldPreventDamageTeleport.Value);
if (!annoying)
{
if ((lethalDamage && Plugin.backroomsConfig.ShouldPreventDeathTeleport.Value) || (!lethalDamage && Plugin.backroomsConfig.ShouldPreventDamageTeleport.Value))
{
goto IL_0122;
}
}
else if (!Plugin.backroomsConfig.ShouldTeleportAnnoyingPeople.Value)
{
goto IL_0122;
}
Plugin.InfoLog("Lethal or not and Annoying check passed!");
EnemyAI inAnimationWithEnemy = player.inAnimationWithEnemy;
List<string> list = Plugin.backroomsConfig.PreventBackroomsTeleportEnemies.Value.ToLower().Replace(" ", "").Split(",")
.ToList();
if ((Object)(object)inAnimationWithEnemy != (Object)null && list.Contains(inAnimationWithEnemy.enemyType.enemyName.ToLower()))
{
return false;
}
Plugin.InfoLog("AI check passed!");
int value = (annoying ? Plugin.backroomsConfig.TeleportAnnoyingPeopleChance : (lethalDamage ? Plugin.backroomsConfig.TeleportLethalDamageChance : Plugin.backroomsConfig.TeleportNonLethalDamageChance)).Value;
Plugin.InfoLog($"Teleport chance: {value}!");
int num = Random.Range(1, 100);
Plugin.InfoLog($"Rolled chance: {num}!");
if (num > value)
{
return false;
}
Plugin.InfoLog("Chance check passed!");
return true;
IL_0122:
return false;
}
internal static void TeleportPlayerToBackrooms(PlayerControllerB player, bool spawnBody = false, Vector3 bodyVelocity = default(Vector3), CauseOfDeath causeOfDeath = 0, int deathAnimation = 0, bool lethalDamage = true, bool annoying = false)
{
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
Plugin.InfoLog("Teleport To Backrooms method!");
EnemyAI inAnimationWithEnemy = player.inAnimationWithEnemy;
int enemyId = (((Object)(object)inAnimationWithEnemy == (Object)null) ? (-1) : inAnimationWithEnemy.thisEnemyIndex);
EnemyFixes(inAnimationWithEnemy);
Plugin.InfoLog("Enemy Fixes passed!");
if (ShouldDropItems(lethalDamage, annoying))
{
player.DropAllHeldItemsAndSync();
}
DisablePlayerDeath(2, player);
Plugin.InfoLog("Sending player to backrooms!");
Backrooms.Instance.TeleportToBackroomsServerRpc((int)player.playerClientId);
if (Plugin.enableSoundReplace && player.playerClientId == StartOfRound.Instance.localPlayerController.playerClientId)
{
for (int i = 1; i <= 4; i++)
{
int num = i - 1;
AudioClip newClip = Plugin.CarpetSounds[num];
SoundToolsWrapper.ReplaceAudioClip($"WoodStep{i}", newClip);
}
((Component)player).gameObject.AddComponent<MusicPlayer>();
}
if (Plugin.backroomsConfig.ShouldSpawnDeadBody != null)
{
Debug.Assert(Plugin.backroomsConfig.ShouldSpawnDeadBody != null, "Plugin.BackroomsConfig.ShouldSpawnDeadBody != null");
if (Plugin.backroomsConfig.ShouldSpawnDeadBody.Value && spawnBody)
{
Plugin.InfoLog("Spawning body!");
RpcCollection.Instance.SpawnDeadBodyServerRpc((int)player.playerClientId, bodyVelocity, causeOfDeath, deathAnimation, enemyId);
}
}
}
private static bool ShouldDropItems(bool lethalDamage, bool annoying)
{
int num;
switch (Plugin.backroomsConfig.DropHeldItemsMode.Value)
{
case DropHeldItemsMode.DropAllOnAnnoyingAndDeath:
num = 0;
goto IL_003a;
case DropHeldItemsMode.DropAllOnDeath:
num = 1;
goto IL_003a;
case DropHeldItemsMode.DropAllOnAnnoying:
if (!annoying)
{
break;
}
goto case DropHeldItemsMode.DropAll;
case DropHeldItemsMode.DropAll:
{
return true;
}
IL_003a:
if (!lethalDamage)
{
if (num == 0)
{
goto case DropHeldItemsMode.DropAllOnAnnoying;
}
if (num == 1)
{
break;
}
}
goto case DropHeldItemsMode.DropAll;
}
return false;
}
}
[BepInPlugin("TestAccount666.RealBackroomsPatch", "RealBackroomsPatch", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const int CARPET_SOUNDS_SIZE = 4;
private static Plugin _instance;
public static BackroomsConfig backroomsConfig;
public static readonly AudioClip[] CarpetSounds = (AudioClip[])(object)new AudioClip[4];
public static bool enableSoundReplace;
public static readonly List<AudioClip> MusicSounds = new List<AudioClip>();
private void Awake()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
_instance = this;
WarningLog("This Mod is my very first Mod and is still work in progress.");
backroomsConfig = new BackroomsConfig("TestAccount666.RealBackroomsPatch", ((BaseUnityPlugin)this).Config);
Harmony val = new Harmony("TestAccount666.RealBackroomsPatch");
InfoLog("Creating patches!");
val.PatchAll(typeof(Patches));
val.PatchAll(typeof(LightFlickerEffect));
val.PatchAll(typeof(RpcCollectionLoader));
val.PatchAll(typeof(SmilerPatch));
if (DependencyChecker.IsGroanTubeModInstalled())
{
val.PatchAll(typeof(GroanTubePatch));
}
enableSoundReplace = DependencyChecker.IsSoundToolsModInstalled();
InfoLog("Unpatching Backrooms Mod!");
Patches.UnpatchDamagePlayerMethod(val);
Patches.UnpatchKillPlayerMethod(val);
Type[] types = Assembly.GetExecutingAssembly().GetTypes();
Type[] array = types;
foreach (Type type in array)
{
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo[] array2 = methods;
foreach (MethodInfo methodInfo in array2)
{
object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false);
if (customAttributes.Length != 0)
{
methodInfo.Invoke(null, null);
}
}
}
((MonoBehaviour)this).StartCoroutine(LoadAudioClips());
((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin RealBackroomsPatch is loaded!");
}
internal static void DebugLog(string msg)
{
((BaseUnityPlugin)_instance).Logger.LogDebug((object)msg);
}
internal static void InfoLog(string msg)
{
((BaseUnityPlugin)_instance).Logger.LogInfo((object)msg);
}
internal static void WarningLog(string msg)
{
((BaseUnityPlugin)_instance).Logger.LogWarning((object)msg);
}
internal static void ErrorLog(string msg)
{
((BaseUnityPlugin)_instance).Logger.LogError((object)msg);
}
private static IEnumerator LoadAudioClips()
{
string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
InfoLog("Loading Carpet Step Sounds...");
Debug.Assert(assemblyDirectory != null, "assemblyDirectory != null");
string audioPath = Path.Combine(assemblyDirectory, "sounds");
audioPath = (Directory.Exists(audioPath) ? audioPath : Path.Combine(assemblyDirectory));
string carpetAudioPath2 = Path.Combine(audioPath, "CarpetSound");
carpetAudioPath2 = (Directory.Exists(carpetAudioPath2) ? carpetAudioPath2 : Path.Combine(assemblyDirectory));
for (int index = 1; index <= 4; index++)
{
int sound = index - 1;
AudioClip carpetAudioClip = LoadAudioClipFromFile(new Uri(Path.Combine(carpetAudioPath2, $"CarpetStep{index}.wav")), $"CarpetStep{index}", (AudioType)20);
CarpetSounds[sound] = carpetAudioClip;
InfoLog("Loaded clip '" + ((Object)carpetAudioClip).name + "'!");
}
InfoLog("Loading Music...");
string musicAudioPath2 = Path.Combine(audioPath, "Music");
musicAudioPath2 = (Directory.Exists(musicAudioPath2) ? musicAudioPath2 : Path.Combine(assemblyDirectory));
foreach (string file in Directory.EnumerateFiles(musicAudioPath2))
{
string fileName = Path.GetFileName(file);
if (fileName.ToLower().EndsWith(".ogg") && fileName.ToLower().StartsWith("music"))
{
Uri filePath = new Uri(file);
string text = fileName;
AudioClip musicAudioClip = LoadAudioClipFromFile(filePath, text.Substring(0, text.Length - 4), (AudioType)14);
MusicSounds.Add(musicAudioClip);
InfoLog("Loaded clip '" + ((Object)musicAudioClip).name + "'!");
}
}
yield break;
}
private static AudioClip LoadAudioClipFromFile(Uri filePath, string name, AudioType audioType = 20)
{
//IL_0002: 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)
//IL_002e: Invalid comparison between Unknown and I4
UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip(filePath, audioType);
try
{
UnityWebRequestAsyncOperation val = audioClip.SendWebRequest();
while (!((AsyncOperation)val).isDone)
{
Thread.Sleep(100);
}
if ((int)audioClip.result != 1)
{
ErrorLog("Failed to load AudioClip: " + audioClip.error);
return null;
}
AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip);
((Object)content).name = name;
return content;
}
finally
{
((IDisposable)audioClip)?.Dispose();
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "TestAccount666.RealBackroomsPatch";
public const string PLUGIN_NAME = "RealBackroomsPatch";
public const string PLUGIN_VERSION = "1.1.0";
}
public class RpcCollection : NetworkBehaviour
{
public static RpcCollection Instance { get; private set; }
public override void OnNetworkSpawn()
{
Plugin.InfoLog("RpcCollection network spawned!");
if ((Object)(object)NetworkManager.Singleton == (Object)null)
{
Plugin.ErrorLog("NetworkManager.Singleton couldn't be found?!");
return;
}
if ((NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) && (Object)(object)Instance != (Object)null && (Object)(object)((Component)Instance).gameObject != (Object)null)
{
((Component)Instance).gameObject.GetComponent<NetworkObject>().Despawn(true);
}
Instance = this;
}
[ClientRpc]
public void SpawnDeadBodyClientRpc(int playerId, Vector3 bodyVelocity, CauseOfDeath causeOfDeath, int deathAnimation, int enemyId)
{
//IL_0034: 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)
Plugin.InfoLog("Spawn dead body ClientRpc!");
PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerId];
EnemyAI enemyAI = ((enemyId != -1) ? RoundManager.Instance.SpawnedEnemies[enemyId] : null);
Patches.SpawnDeadBody(player, bodyVelocity, causeOfDeath, deathAnimation, enemyAI, ((NetworkBehaviour)this).IsServer);
}
[ServerRpc(RequireOwnership = false)]
public void SpawnDeadBodyServerRpc(int playerId, Vector3 bodyVelocity, CauseOfDeath causeOfDeath, int deathAnimation, int enemyId)
{
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: 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_0059: Unknown result type (might be due to invalid IL or missing references)
Plugin.InfoLog("Spawn body ServerRpc!");
PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerId];
EnemyAI enemyAI = ((enemyId != -1) ? RoundManager.Instance.SpawnedEnemies[enemyId] : null);
if (((NetworkBehaviour)this).IsServer && !((NetworkBehaviour)this).IsHost)
{
Plugin.InfoLog("Server spawning DeadBody!");
Patches.SpawnDeadBody(player, bodyVelocity, causeOfDeath, deathAnimation, enemyAI, ((NetworkBehaviour)this).IsServer);
}
else
{
SpawnDeadBodyClientRpc(playerId, bodyVelocity, causeOfDeath, deathAnimation, enemyId);
}
}
[ClientRpc]
public void TeleportPlayerToBackroomsClientRpc(int playerId, bool spawnBody = false, Vector3 bodyVelocity = default(Vector3), CauseOfDeath causeOfDeath = 0, int deathAnimation = 0, bool lethalDamage = true, bool negativeDamage = false, bool annoying = false)
{
//IL_001b: 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)
Plugin.InfoLog("Teleport Player ClientRcp!");
PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerId];
Patches.TeleportPlayerToBackrooms(player, spawnBody, bodyVelocity, causeOfDeath, deathAnimation, lethalDamage, annoying);
}
[ServerRpc(RequireOwnership = false)]
public void TeleportPlayerToBackroomsServerRpc(int playerId, bool spawnBody = false, Vector3 bodyVelocity = default(Vector3), CauseOfDeath causeOfDeath = 0, int deathAnimation = 0, bool lethalDamage = true, bool negativeDamage = false, bool annoying = false)
{
//IL_0052: 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_003f: 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)
Plugin.InfoLog("Teleport Player ServerRcp!");
PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerId];
if (((NetworkBehaviour)this).IsServer && !((NetworkBehaviour)this).IsHost)
{
Plugin.InfoLog("Server but not host Teleport!");
Patches.TeleportPlayerToBackrooms(player, spawnBody, bodyVelocity, causeOfDeath, deathAnimation, lethalDamage, annoying);
}
TeleportPlayerToBackroomsClientRpc(playerId, spawnBody, bodyVelocity, causeOfDeath, deathAnimation, lethalDamage, negativeDamage, annoying);
}
}
[HarmonyPatch]
public class RpcCollectionLoader
{
private static GameObject _networkPrefab;
private static int _networkPrefabInstanceId = -1;
private static int _networkHandlerHostInstanceId = -1;
private static NetworkObject _networkHandlerHost;
[HarmonyPostfix]
[HarmonyPatch(typeof(StartOfRound), "OnDestroy")]
public static void AfterDestroy()
{
if ((Object)(object)_networkPrefab != (Object)null)
{
RpcCollection component = _networkPrefab.GetComponent<RpcCollection>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
Object.Destroy((Object)(object)_networkPrefab);
_networkPrefab = null;
_networkPrefabInstanceId = -1;
}
if (!((Object)(object)_networkHandlerHost == (Object)null))
{
Object.Destroy((Object)(object)_networkHandlerHost);
_networkHandlerHost = null;
_networkPrefabInstanceId = -1;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(StartOfRound), "Awake")]
public static void SpawnNetworkHandler1()
{
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
_networkPrefab = NetworkPrefabs.CreateNetworkPrefab("RpcCollectionHandler");
_networkPrefab.AddComponent<RpcCollection>();
_networkPrefabInstanceId = ((Object)_networkPrefab).GetInstanceID();
Object.DontDestroyOnLoad((Object)(object)_networkPrefab);
if ((NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) && (!((Object)(object)_networkHandlerHost != (Object)null) || !(Object.FindObjectFromInstanceID(_networkHandlerHostInstanceId) != (Object)null)))
{
_networkHandlerHost = Object.Instantiate<GameObject>(_networkPrefab, Vector3.zero, Quaternion.identity).GetComponent<NetworkObject>();
_networkHandlerHost.Spawn(false);
Object.DontDestroyOnLoad((Object)(object)_networkHandlerHost);
_networkHandlerHostInstanceId = ((Object)_networkHandlerHost).GetInstanceID();
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(StartOfRound), "OnEnable")]
public static void SpawnNetworkHandler2()
{
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_networkPrefab == (Object)null || Object.FindObjectFromInstanceID(_networkPrefabInstanceId) == (Object)null)
{
_networkPrefab = NetworkPrefabs.CreateNetworkPrefab("RpcCollectionHandler");
_networkPrefab.AddComponent<RpcCollection>();
_networkPrefabInstanceId = ((Object)_networkPrefab).GetInstanceID();
Object.DontDestroyOnLoad((Object)(object)_networkPrefab);
}
if ((NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer) && (!((Object)(object)_networkHandlerHost != (Object)null) || !(Object.FindObjectFromInstanceID(_networkHandlerHostInstanceId) != (Object)null)))
{
_networkHandlerHost = Object.Instantiate<GameObject>(_networkPrefab, Vector3.zero, Quaternion.identity).GetComponent<NetworkObject>();
_networkHandlerHost.Spawn(false);
Object.DontDestroyOnLoad((Object)(object)_networkHandlerHost);
_networkHandlerHostInstanceId = ((Object)_networkHandlerHost).GetInstanceID();
}
}
}
[HarmonyPatch(typeof(Smiler))]
public static class SmilerPatch
{
[HarmonyPatch("Start")]
[HarmonyPostfix]
public static void FixSmiler(Smiler __instance)
{
GameObject gameObject = ((Component)((Component)__instance).gameObject.transform.Find("KillBox")).gameObject;
KillBox component = gameObject.GetComponent<KillBox>();
Object.Destroy((Object)(object)component);
gameObject.AddComponent<FixedKillBox>();
}
}
internal static class SoundToolsWrapper
{
public static void RestoreAudioClip(string name)
{
SoundTool.RestoreAudioClip(name);
}
public static void ReplaceAudioClip(string originalName, AudioClip newClip)
{
SoundTool.ReplaceAudioClip(originalName, newClip);
}
}
public static class StartOfRoundPatch
{
public static void SyncBackroomsConfig()
{
if (Plugin.backroomsConfig == null)
{
Plugin.ErrorLog("Config not found, please report this!");
}
else if (((NetworkBehaviour)RoundManager.Instance).IsHost)
{
Plugin.InfoLog("Skipping sync request, since we're the host!");
}
}
}
public static class UnixTime
{
public static long GetCurrentTime()
{
return (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds;
}
}
}