Decompiled source of Vasodilation v1.2.2

tony4twentys-Vasodilation.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using ExitGames.Client.Photon;
using Microsoft.CodeAnalysis;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using PhotonCustomPropsUtils;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Vasodilation")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Vasodilation")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("15fa7750-965f-4249-837f-3d54157b5401")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace VasodilationMod
{
	[BepInPlugin("tony4twentys.Vasodilation", "Vasodilation", "1.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class VasodilationPlugin : BaseUnityPlugin, IInRoomCallbacks, IMatchmakingCallbacks
	{
		[Serializable]
		public struct HostCfg
		{
			public float coldPerSecond;

			public float tickSeconds;

			public float gateOn;

			public float gateOff;
		}

		[CompilerGenerated]
		private sealed class <HostAuthoritativeDriver>d__37 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VasodilationPlugin <>4__this;

			private WaitForSeconds <wait>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <HostAuthoritativeDriver>d__37(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<wait>5__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<wait>5__1 = new WaitForSeconds(Mathf.Max(0.05f, Synced.tickSeconds));
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				if (<>4__this._allowVaso)
				{
					if (<>4__this._cfgVerbose.Value)
					{
						((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Vaso] Tick loop: applying perSec={Synced.coldPerSecond} total={Synced.tickSeconds}");
					}
					<>4__this.ApplyTick(Synced.coldPerSecond, Synced.tickSeconds);
				}
				<>2__current = <wait>5__1;
				<>1__state = 1;
				return true;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private const string ROOM_CFG_KEY = "VASO_CFG_V1";

		private ConfigEntry<float> _cfgColdPerSecond;

		private ConfigEntry<float> _cfgTickSeconds;

		private ConfigEntry<float> _cfgGateOn;

		private ConfigEntry<float> _cfgGateOff;

		private ConfigEntry<bool> _cfgVerbose;

		public static HostCfg Synced;

		private Coroutine _hostLoop;

		private float _runningTickSeconds;

		private PhotonScopedManager _photonManager;

		public bool IsHost = false;

		private bool _allowVaso = false;

		private void Awake()
		{
			_cfgColdPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ColdPerSecond", -0.06f, string.Empty);
			_cfgTickSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickSeconds", 1f, string.Empty);
			_cfgGateOn = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ColdGateOn", 0.025f, string.Empty);
			_cfgGateOff = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ColdGateOff", 0f, string.Empty);
			_cfgVerbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogs", false, string.Empty);
			Synced = BuildFromHostConfig();
			_runningTickSeconds = Synced.tickSeconds;
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Awake: initial cfg built; waiting for scene/Photon events");
			}
			_cfgColdPerSecond.SettingChanged += delegate
			{
				OnHostConfigChanged();
			};
			_cfgTickSeconds.SettingChanged += delegate
			{
				OnHostConfigChanged();
			};
			_cfgGateOn.SettingChanged += delegate
			{
				OnHostConfigChanged();
			};
			_cfgGateOff.SettingChanged += delegate
			{
				OnHostConfigChanged();
			};
			SceneManager.activeSceneChanged += OnSceneChanged;
			InitializePhotonManager();
		}

		private void OnEnable()
		{
			PhotonNetwork.AddCallbackTarget((object)this);
		}

		private void OnDisable()
		{
			PhotonNetwork.RemoveCallbackTarget((object)this);
		}

		private void OnDestroy()
		{
			SceneManager.activeSceneChanged -= OnSceneChanged;
		}

		private void OnSceneChanged(Scene oldScene, Scene newScene)
		{
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[Vaso] Scene changed: " + ((Scene)(ref oldScene)).name + " -> " + ((Scene)(ref newScene)).name));
			}
			RestartHostLoopIfNeeded();
		}

		public void OnJoinedRoom()
		{
			CheckHostStatus();
		}

		public void OnCreatedRoom()
		{
		}

		public void OnCreateRoomFailed(short returnCode, string message)
		{
		}

		public void OnFriendListUpdate(List<FriendInfo> friendList)
		{
		}

		public void OnJoinRandomFailed(short returnCode, string message)
		{
		}

		public void OnJoinRoomFailed(short returnCode, string message)
		{
		}

		void IInRoomCallbacks.OnPlayerEnteredRoom(Player newPlayer)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PublishConfig();
			}
		}

		void IInRoomCallbacks.OnPlayerLeftRoom(Player otherPlayer)
		{
		}

		void IInRoomCallbacks.OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
		}

		void IInRoomCallbacks.OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
		}

		void IInRoomCallbacks.OnMasterClientSwitched(Player newMasterClient)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PublishConfig();
			}
			TryStartOrStopHostLoop();
		}

		private HostCfg BuildFromHostConfig()
		{
			HostCfg result = default(HostCfg);
			result.coldPerSecond = _cfgColdPerSecond.Value;
			result.tickSeconds = Mathf.Max(0.05f, _cfgTickSeconds.Value);
			result.gateOn = Mathf.Max(0f, _cfgGateOn.Value);
			result.gateOff = Mathf.Max(0f, _cfgGateOff.Value);
			return result;
		}

		private static string PackCfg(HostCfg c)
		{
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			return c.coldPerSecond.ToString(invariantCulture) + "|" + c.tickSeconds.ToString(invariantCulture) + "|" + c.gateOn.ToString(invariantCulture) + "|" + c.gateOff.ToString(invariantCulture);
		}

		private static HostCfg UnpackCfg(string s)
		{
			CultureInfo invariantCulture = CultureInfo.InvariantCulture;
			string[] array = (s ?? string.Empty).Split(new char[1] { '|' });
			HostCfg hostCfg = default(HostCfg);
			hostCfg.coldPerSecond = -0.06f;
			hostCfg.tickSeconds = 1f;
			hostCfg.gateOn = 0.025f;
			hostCfg.gateOff = 0f;
			HostCfg result = hostCfg;
			if (array.Length >= 4)
			{
				float.TryParse(array[0], NumberStyles.Float, invariantCulture, out result.coldPerSecond);
				float.TryParse(array[1], NumberStyles.Float, invariantCulture, out result.tickSeconds);
				float.TryParse(array[2], NumberStyles.Float, invariantCulture, out result.gateOn);
				float.TryParse(array[3], NumberStyles.Float, invariantCulture, out result.gateOff);
			}
			return result;
		}

		private void OnHostConfigChanged()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				if (_cfgVerbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Host config changed; publishing to room");
				}
				PublishConfig();
			}
		}

		private void PublishConfig()
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom == null)
			{
				return;
			}
			Synced = BuildFromHostConfig();
			string text = PackCfg(Synced);
			if (PhotonNetwork.IsMasterClient && _photonManager != null)
			{
				if (_cfgVerbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Setting room property via PhotonCustomPropsUtils");
				}
				_photonManager.SetRoomProperty("VASO_CFG_V1", (object)text);
				if (_cfgVerbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Host published config: perSec={Synced.coldPerSecond} tick={Synced.tickSeconds} gates=({Synced.gateOn},{Synced.gateOff})");
				}
				RestartHostLoopIfNeeded();
			}
			else if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] PhotonCustomPropsUtils not ready; skipping direct property set to avoid duplication");
			}
		}

		private void RestartHostLoopIfNeeded()
		{
			if (Math.Abs(_runningTickSeconds - Synced.tickSeconds) > 0.0001f)
			{
				StopHostLoop();
				TryStartOrStopHostLoop();
			}
		}

		private void TryStartOrStopHostLoop()
		{
			if (_allowVaso)
			{
				if (_hostLoop == null)
				{
					_runningTickSeconds = Synced.tickSeconds;
					if (_cfgVerbose.Value)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Starting tick loop");
					}
					_hostLoop = ((MonoBehaviour)this).StartCoroutine(HostAuthoritativeDriver());
				}
			}
			else
			{
				if (_cfgVerbose.Value && _hostLoop != null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Stopping tick loop (not allowed)");
				}
				StopHostLoop();
			}
		}

		private void StopHostLoop()
		{
			if (_hostLoop != null)
			{
				((MonoBehaviour)this).StopCoroutine(_hostLoop);
				_hostLoop = null;
			}
		}

		[IteratorStateMachine(typeof(<HostAuthoritativeDriver>d__37))]
		private IEnumerator HostAuthoritativeDriver()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <HostAuthoritativeDriver>d__37(0)
			{
				<>4__this = this
			};
		}

		private Character FindLocalCharacter()
		{
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if ((Object)(object)allCharacter != (Object)null && (Object)(object)((MonoBehaviourPun)allCharacter).photonView != (Object)null && ((MonoBehaviourPun)allCharacter).photonView.IsMine)
				{
					return allCharacter;
				}
			}
			return null;
		}

		private void ApplyTick(float perSecond, float totalTime)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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_00f7: Expected O, but got Unknown
			Character val = FindLocalCharacter();
			if ((Object)(object)val == (Object)null || val.refs == null || (Object)(object)val.refs.afflictions == (Object)null)
			{
				if (_cfgVerbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] No local character; skip tick");
				}
				return;
			}
			bool flag = (Object)(object)val.data != (Object)null && val.data.isSprinting;
			float currentStatus = val.refs.afflictions.GetCurrentStatus((STATUSTYPE)2);
			if (!flag || currentStatus <= Synced.gateOff)
			{
				if (_cfgVerbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Tick ignored: sprinting={flag} cold={currentStatus}");
				}
				return;
			}
			Affliction_AdjustColdOverTime val2 = new Affliction_AdjustColdOverTime
			{
				statusPerSecond = perSecond,
				totalTime = totalTime,
				character = val
			};
			val.refs.afflictions.AddAffliction((Affliction)(object)val2, false);
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Tick applied: per={perSecond} for {totalTime}s; cold={currentStatus}");
			}
		}

		private void InitializePhotonManager()
		{
			if (PhotonCustomPropsUtilsPlugin.IsReady)
			{
				SetupPhotonManager();
			}
			else
			{
				PhotonCustomPropsUtilsPlugin.OnReady += SetupPhotonManager;
			}
		}

		private void SetupPhotonManager()
		{
			_photonManager = PhotonCustomPropsUtilsPlugin.GetManager("tony4twentys.Vasodilation");
			_photonManager.RegisterOnJoinedRoom((Action<Player>)delegate
			{
				CheckHostStatus();
			});
			_photonManager.RegisterRoomProperty<string>("VASO_CFG_V1", (RoomEventType)2, (Action<string>)delegate(string configData)
			{
				if (!IsHost && !string.IsNullOrEmpty(configData))
				{
					HostCfg synced = Synced;
					Synced = UnpackCfg(configData);
					if (_cfgVerbose.Value)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Config updated from room (PCPU): perSec={Synced.coldPerSecond} tick={Synced.tickSeconds} gates=({Synced.gateOn},{Synced.gateOff}) (was {synced.coldPerSecond}/{synced.tickSeconds})");
					}
					_allowVaso = true;
					RestartHostLoopIfNeeded();
				}
			});
		}

		private void CheckHostStatus()
		{
			if (!PhotonNetwork.InRoom)
			{
				return;
			}
			if (PhotonNetwork.IsMasterClient)
			{
				if (!IsHost)
				{
					IsHost = true;
					_allowVaso = true;
					if (_cfgVerbose.Value)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Joined room as HOST");
					}
					PublishConfig();
				}
			}
			else if (IsHost)
			{
				IsHost = false;
				_allowVaso = false;
				if (_cfgVerbose.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Joined room as CLIENT; awaiting config");
				}
			}
			TryStartOrStopHostLoop();
		}

		public void OnLeftRoom()
		{
			IsHost = false;
			_allowVaso = false;
			StopHostLoop();
		}
	}
}