Decompiled source of Vasodilation v1.2.1

tony4twentys-Vasodilation.dll

Decompiled 2 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 Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
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 VasodilationMod;

[BepInPlugin("tony4twentys.Vasodilation", "Vasodilation", "1.2.0")]
public class VasodilationPlugin : BaseUnityPlugin, IInRoomCallbacks, IMatchmakingCallbacks, IOnEventCallback
{
	[Serializable]
	public struct HostCfg
	{
		public float coldPerSecond;

		public float tickSeconds;

		public float gateOn;

		public float gateOff;
	}

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

		private object <>2__current;

		public VasodilationPlugin <>4__this;

		private WaitForSeconds <wait>5__1;

		private Player[] <players>5__2;

		private int <i>5__3;

		private int <actor>5__4;

		private object[] <payload>5__5;

		private RaiseEventOptions <opts>5__6;

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

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

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

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<wait>5__1 = null;
			<players>5__2 = null;
			<payload>5__5 = null;
			<opts>5__6 = 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
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			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 (PhotonNetwork.IsMasterClient)
			{
				<players>5__2 = PhotonNetwork.PlayerList;
				<i>5__3 = 0;
				while (<i>5__3 < <players>5__2.Length)
				{
					<actor>5__4 = <players>5__2[<i>5__3].ActorNumber;
					<payload>5__5 = new object[2] { Synced.coldPerSecond, Synced.tickSeconds };
					RaiseEventOptions val = new RaiseEventOptions();
					val.TargetActors = new int[1] { <actor>5__4 };
					<opts>5__6 = val;
					PhotonNetwork.RaiseEvent((byte)113, (object)<payload>5__5, <opts>5__6, SendOptions.SendUnreliable);
					if (<>4__this._cfgVerbose.Value)
					{
						((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"[Vaso] Sent tick -> actor {<actor>5__4}");
					}
					<payload>5__5 = null;
					<opts>5__6 = null;
					<i>5__3++;
				}
				<players>5__2 = null;
			}
			<>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 const byte EVT_VASO_TICK = 113;

	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 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;
		_cfgColdPerSecond.SettingChanged += delegate
		{
			OnHostConfigChanged();
		};
		_cfgTickSeconds.SettingChanged += delegate
		{
			OnHostConfigChanged();
		};
		_cfgGateOn.SettingChanged += delegate
		{
			OnHostConfigChanged();
		};
		_cfgGateOff.SettingChanged += delegate
		{
			OnHostConfigChanged();
		};
		SceneManager.activeSceneChanged += OnSceneChanged;
	}

	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)
	{
		TryReadConfigFromRoom();
		RestartHostLoopIfNeeded();
	}

	public void OnJoinedRoom()
	{
		if (PhotonNetwork.IsMasterClient)
		{
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Joined room as HOST");
			}
			PublishConfig();
		}
		else
		{
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Vaso] Joined room as CLIENT; reading config");
			}
			TryReadConfigFromRoom();
		}
		TryStartOrStopHostLoop();
	}

	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)
	{
	}

	public void OnLeftRoom()
	{
	}

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

	void IInRoomCallbacks.OnPlayerLeftRoom(Player otherPlayer)
	{
	}

	void IInRoomCallbacks.OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
	{
		if (propertiesThatChanged != null && ((Dictionary<object, object>)(object)propertiesThatChanged).ContainsKey((object)"VASO_CFG_V1") && propertiesThatChanged[(object)"VASO_CFG_V1"] is string s)
		{
			HostCfg synced = Synced;
			Synced = UnpackCfg(s);
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Config updated from room: perSec={Synced.coldPerSecond} tick={Synced.tickSeconds} gates=({Synced.gateOn},{Synced.gateOff}) (was {synced.coldPerSecond}/{synced.tickSeconds})");
			}
			RestartHostLoopIfNeeded();
		}
	}

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

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

	public void OnEvent(EventData photonEvent)
	{
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Expected O, but got Unknown
		if (photonEvent == null || photonEvent.Code != 113 || !(photonEvent.CustomData is object[] array) || array.Length < 2)
		{
			return;
		}
		float num = Convert.ToSingle(array[0]);
		float num2 = Convert.ToSingle(array[1]);
		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 = num,
			totalTime = num2,
			character = val
		};
		val.refs.afflictions.AddAffliction((Affliction)(object)val2, false);
		if (_cfgVerbose.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Tick applied: per={num} for {num2}s; cold={currentStatus}");
		}
	}

	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 TryReadConfigFromRoom()
	{
		Room currentRoom = PhotonNetwork.CurrentRoom;
		if (currentRoom != null && ((RoomInfo)currentRoom).CustomProperties != null && ((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).TryGetValue((object)"VASO_CFG_V1", out object value) && value is string s)
		{
			Synced = UnpackCfg(s);
		}
	}

	private void OnHostConfigChanged()
	{
		if (PhotonNetwork.IsMasterClient)
		{
			PublishConfig();
		}
	}

	private void PublishConfig()
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Expected O, but got Unknown
		Room currentRoom = PhotonNetwork.CurrentRoom;
		if (currentRoom != null)
		{
			Synced = BuildFromHostConfig();
			string text = PackCfg(Synced);
			Hashtable val = new Hashtable { [(object)"VASO_CFG_V1"] = text };
			currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			if (_cfgVerbose.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"[Vaso] Host published config: perSec={Synced.coldPerSecond} tick={Synced.tickSeconds} gates=({Synced.gateOn},{Synced.gateOff})");
			}
			RestartHostLoopIfNeeded();
		}
	}

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

	private void TryStartOrStopHostLoop()
	{
		if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
		{
			if (_hostLoop == null)
			{
				_runningTickSeconds = Synced.tickSeconds;
				_hostLoop = ((MonoBehaviour)this).StartCoroutine(HostAuthoritativeDriver());
			}
		}
		else
		{
			StopHostLoop();
		}
	}

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

	[IteratorStateMachine(typeof(<HostAuthoritativeDriver>d__38))]
	private IEnumerator HostAuthoritativeDriver()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <HostAuthoritativeDriver>d__38(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;
	}
}