Decompiled source of PushASA v1.0.0

PushASA.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace PushASA;

[HarmonyPatch(typeof(ClientPlayerCharacter))]
public static class ClientPlayerCharacter_Patches
{
	private static PushComponent pushComponent;

	internal static bool _audioCaptureEnabled;

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ClientPlayerCharacter), "Update")]
	private static void Update(ClientPlayerCharacter __instance)
	{
		//IL_0013: 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 (!__instance.pv.IsMine || !Input.GetKeyDown(PushASA.config_PushKey.Value))
		{
			return;
		}
		if (PushASA.config_EnableDebugLogs.Value)
		{
			PushASA.Instance.mls.LogInfo((object)$"{PushASA.config_PushKey.Value} key pressed - attempting to push");
		}
		if ((Object)(object)pushComponent == (Object)null)
		{
			pushComponent = NetworkHandler.GetPushComponent();
			if ((Object)(object)pushComponent == (Object)null && PushASA.config_EnableDebugLogs.Value)
			{
				PushASA.Instance.mls.LogWarning((object)"PushComponent not found!");
				return;
			}
		}
		pushComponent?.PushServerRpc(__instance.pv.ViewID);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(NetworkManager), "OnJoinedRoom")]
	private static void OnJoinedRoom(NetworkManager __instance)
	{
		_audioCaptureEnabled = true;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(NetworkManager), "OnCreatedRoom")]
	private static void OnCreatedRoom(NetworkManager __instance)
	{
		_audioCaptureEnabled = true;
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ClientPlayerCharacter), "Awake")]
	private static void Awake_Postfix(ClientPlayerCharacter __instance)
	{
		if ((Object)(object)((Component)__instance).GetComponent<PushRPCHandler>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<PushRPCHandler>();
		}
	}
}
public class PushRPCHandler : MonoBehaviourPunCallbacks
{
	[CompilerGenerated]
	private sealed class <LoadFootstepAudioCoroutine>d__8 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public PushRPCHandler <>4__this;

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

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

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

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

		private bool MoveNext()
		{
			int num = <>1__state;
			PushRPCHandler pushRPCHandler = <>4__this;
			switch (num)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				if (pushRPCHandler.audioLoadAttempted)
				{
					return false;
				}
				pushRPCHandler.audioLoadAttempted = true;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				try
				{
					pushRPCHandler.TryGetFootstepAudioFromScene();
				}
				catch (Exception ex)
				{
					PushASA.Instance.mls.LogError((object)("Failed to load footstep audio: " + ex.Message));
				}
				if (pushRPCHandler.footstepClips != null && pushRPCHandler.footstepClips.Length != 0)
				{
					pushRPCHandler.CopyAudioSettingsFromExistingSources();
					pushRPCHandler.audioLoaded = true;
				}
				else
				{
					PushASA.Instance.mls.LogError((object)"Failed to load any footstep audio");
					pushRPCHandler.audioLoaded = false;
				}
				pushRPCHandler.loadCoroutine = null;
				return false;
			}
		}

		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 PhotonView photonView;

	private AudioSource pushAudioSource;

	private AudioClip[] footstepClips;

	private bool audioLoaded;

	private bool audioLoadAttempted;

	private Coroutine loadCoroutine;

	private void Awake()
	{
		photonView = ((Component)this).GetComponent<PhotonView>();
		pushAudioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
		pushAudioSource.spatialBlend = 0.8f;
		pushAudioSource.volume = PushASA.config_PushVolume.Value;
		pushAudioSource.playOnAwake = false;
		pushAudioSource.maxDistance = 10f;
		pushAudioSource.rolloffMode = (AudioRolloffMode)0;
		if (PushASA.config_EnableDebugLogs.Value)
		{
			PushASA.Instance.mls.LogInfo((object)"Created dedicated AudioSource for push sounds");
		}
	}

	private void Update()
	{
		if (!audioLoadAttempted && ClientPlayerCharacter_Patches._audioCaptureEnabled && loadCoroutine == null)
		{
			loadCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadFootstepAudioCoroutine());
		}
	}

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

	private void TryGetFootstepAudioFromScene()
	{
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Invalid comparison between Unknown and I4
		ClientPlayerAudioController component = ((Component)this).GetComponent<ClientPlayerAudioController>();
		if ((Object)(object)component == (Object)null)
		{
			PushASA.Instance.mls.LogWarning((object)"ClientPlayerAudioController not found on this GameObject");
			return;
		}
		if (component.footstepGroups == null || component.footstepGroups.Length == 0)
		{
			PushASA.Instance.mls.LogWarning((object)"footstepGroups is null or empty");
			return;
		}
		FootstepGroup val = null;
		FootstepGroup[] footstepGroups = component.footstepGroups;
		foreach (FootstepGroup val2 in footstepGroups)
		{
			if ((Object)(object)val2 != (Object)null && (int)val2.surface == 4)
			{
				val = val2;
				break;
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			PushASA.Instance.mls.LogWarning((object)"Carpet FootstepGroup not found");
			return;
		}
		List<AudioClip> list = new List<AudioClip>();
		if (val.separateRunClips && val.runClips != null && val.runClips.Length != 0)
		{
			list.AddRange(val.runClips);
		}
		else if (val.walkClips != null && val.walkClips.Length != 0)
		{
			list.AddRange(val.walkClips);
		}
		if (list.Count > 0)
		{
			footstepClips = list.ToArray();
			if (PushASA.config_EnableDebugLogs.Value)
			{
				PushASA.Instance.mls.LogInfo((object)$"Successfully loaded {list.Count} footstep clips from ClientPlayerAudioController");
			}
		}
		else
		{
			PushASA.Instance.mls.LogWarning((object)"No footstep clips loaded from Carpet group");
		}
	}

	private void CopyAudioSettingsFromExistingSources()
	{
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			AudioSource[] array = Object.FindObjectsOfType<AudioSource>();
			foreach (AudioSource val in array)
			{
				if (((Object)val).name.Contains("Player") || ((Object)val).name.Contains("Footstep") || ((Object)val).name.Contains("Character"))
				{
					pushAudioSource.spatialBlend = val.spatialBlend;
					pushAudioSource.priority = val.priority;
					pushAudioSource.pitch = val.pitch;
					pushAudioSource.panStereo = val.panStereo;
					pushAudioSource.spread = val.spread;
					pushAudioSource.dopplerLevel = val.dopplerLevel;
					pushAudioSource.rolloffMode = val.rolloffMode;
					pushAudioSource.minDistance = val.minDistance;
					pushAudioSource.maxDistance = val.maxDistance;
					if ((Object)(object)val.outputAudioMixerGroup != (Object)null)
					{
						pushAudioSource.outputAudioMixerGroup = val.outputAudioMixerGroup;
					}
					break;
				}
			}
		}
		catch (Exception ex)
		{
			PushASA.Instance.mls.LogWarning((object)("Failed to copy audio settings: " + ex.Message));
		}
	}

	[PunRPC]
	public void PushPlayerRPC(int pusherViewId, float pushX, float pushY, float pushZ)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = default(Vector3);
		((Vector3)(ref val))..ctor(pushX, pushY, pushZ);
		PlayPushSound();
		if (photonView.IsMine && (Object)(object)PlayerLocomotionController.instance != (Object)null)
		{
			PlayerLocomotionController instance = PlayerLocomotionController.instance;
			instance.velocity += val;
			if (PushASA.config_EnableDebugLogs.Value)
			{
				PushASA.Instance.mls.LogInfo((object)$"Received push RPC: Applied velocity {val}");
			}
		}
	}

	public void DebugPlayPushSound()
	{
		PlayPushSound();
	}

	private void PlayPushSound()
	{
		if ((Object)(object)pushAudioSource == (Object)null)
		{
			if (PushASA.config_EnableDebugLogs.Value)
			{
				PushASA.Instance.mls.LogWarning((object)"Push AudioSource is null!");
			}
		}
		else if (!audioLoaded && !audioLoadAttempted)
		{
			if (loadCoroutine == null)
			{
				loadCoroutine = ((MonoBehaviour)this).StartCoroutine(LoadFootstepAudioCoroutine());
			}
		}
		else if (footstepClips != null && footstepClips.Length != 0)
		{
			AudioClip val = footstepClips[Random.Range(0, footstepClips.Length)];
			pushAudioSource.pitch = Random.Range(0.95f, 1.05f);
			pushAudioSource.PlayOneShot(val);
			if (PushASA.config_EnableDebugLogs.Value)
			{
				PushASA.Instance.mls.LogInfo((object)$"Played push sound: {((Object)val).name} (pitch: {pushAudioSource.pitch:F2})");
			}
		}
		else
		{
			PushASA.Instance.mls.LogWarning((object)"No footstep clips available");
		}
	}
}
[HarmonyPatch]
public class NetworkHandler
{
	private static GameObject pushObject;

	private static PushComponent pushComponent;

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ClientPlayerCharacter), "Start")]
	private static void SpawnNetworkPrefab()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		try
		{
			if (!((Object)(object)pushObject != (Object)null))
			{
				pushObject = new GameObject("PushASA");
				pushComponent = pushObject.AddComponent<PushComponent>();
				Object.DontDestroyOnLoad((Object)(object)pushObject);
				PushASA.Instance.mls.LogInfo((object)"Push system initialized!");
			}
		}
		catch (Exception ex)
		{
			PushASA.Instance.mls.LogError((object)("Failed to initialize push system: " + ex.Message + "\n" + ex.StackTrace));
		}
	}

	public static PushComponent GetPushComponent()
	{
		return pushComponent;
	}
}
[BepInPlugin("FluxTeam.PushASA", "PushASA", "1.0.0")]
public class PushASA : BaseUnityPlugin
{
	public ManualLogSource mls;

	private readonly Harmony harmony = new Harmony("FluxTeam.PushASA");

	public static ConfigEntry<float> config_PushCooldown;

	public static ConfigEntry<float> config_PushForce;

	public static ConfigEntry<float> config_PushRange;

	public static ConfigEntry<float> config_PushCost;

	public static ConfigEntry<float> config_PushVolume;

	public static ConfigEntry<bool> config_EnableDebugLogs;

	public static ConfigEntry<bool> config_DebugPlaySoundAlways;

	public static ConfigEntry<KeyCode> config_PushKey;

	public static PushASA Instance { get; private set; }

	private void Awake()
	{
		Instance = this;
		mls = Logger.CreateLogSource("FluxTeam.PushASA");
		ConfigSetup();
		harmony.PatchAll(typeof(PushASA));
		harmony.PatchAll(typeof(ClientPlayerCharacter_Patches));
		harmony.PatchAll(typeof(NetworkHandler));
		mls.LogInfo((object)"PushASA has initialized!");
	}

	private void ConfigSetup()
	{
		config_PushCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Push Settings", "Cooldown", 0.5f, "How long until the player can push again");
		config_PushForce = ((BaseUnityPlugin)this).Config.Bind<float>("Push Settings", "Force", 12.5f, "How strong the player pushes are");
		config_PushRange = ((BaseUnityPlugin)this).Config.Bind<float>("Push Settings", "Range", 3f, "The distance the player is able to push");
		config_PushCost = ((BaseUnityPlugin)this).Config.Bind<float>("Push Settings", "Stamina Cost", 0.1f, "The stamina cost of each push");
		config_PushKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Push Settings", "Push Key", (KeyCode)101, "The key to press to push other players");
		config_PushVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Push Settings", "Push Sound Volume", 1f, "Volume of the push sound effect (0.0 to 1.0)");
		config_EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Enable Debug Logs", false, "Enable detailed logging for push actions");
		config_DebugPlaySoundAlways = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Always Play Sound", false, "Play push sound even when not hitting a player (for testing audio)");
	}
}
public static class PluginInfo
{
	public const string PLUGIN_GUID = "FluxTeam.PushASA";

	public const string PLUGIN_NAME = "PushASA";

	public const string PLUGIN_VERSION = "1.0.0";
}
public class PushComponent : MonoBehaviour
{
	private Dictionary<int, float> lastPushTimes = new Dictionary<int, float>();

	private float PushCooldown => PushASA.config_PushCooldown.Value;

	private float PushRange => PushASA.config_PushRange.Value;

	private float PushForce => PushASA.config_PushForce.Value;

	private float PushCost => PushASA.config_PushCost.Value;

	public void PushServerRpc(int playerViewId)
	{
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: Unknown result type (might be due to invalid IL or missing references)
		//IL_025c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		bool value = PushASA.config_EnableDebugLogs.Value;
		if (lastPushTimes.TryGetValue(playerViewId, out var value2))
		{
			if (Time.time - value2 < PushCooldown)
			{
				if (value)
				{
					PushASA.Instance.mls.LogInfo((object)$"Push blocked: Cooldown active ({PushCooldown - (Time.time - value2):F2}s remaining)");
				}
				return;
			}
		}
		else
		{
			lastPushTimes.Add(playerViewId, 0f);
		}
		PhotonView val = PhotonView.Find(playerViewId);
		if ((Object)(object)val == (Object)null)
		{
			if (value)
			{
				PushASA.Instance.mls.LogWarning((object)"Push failed: Pusher PhotonView not found");
			}
			return;
		}
		ClientPlayerCharacter component = ((Component)val).GetComponent<ClientPlayerCharacter>();
		if ((Object)(object)component == (Object)null)
		{
			if (value)
			{
				PushASA.Instance.mls.LogWarning((object)"Push failed: Pusher ClientPlayerCharacter not found");
			}
			return;
		}
		Camera main = Camera.main;
		if ((Object)(object)main == (Object)null)
		{
			if (value)
			{
				PushASA.Instance.mls.LogWarning((object)"Push failed: Camera not found");
			}
			return;
		}
		if (!CanPushPlayer(component))
		{
			if (value)
			{
				PushASA.Instance.mls.LogInfo((object)"Push blocked: Player cannot push (in menu, terminal, or low stamina)");
			}
			return;
		}
		int mask = LayerMask.GetMask(new string[1] { "Default" });
		Vector3 forward = ((Component)main).transform.forward;
		Vector3 normalized = ((Vector3)(ref forward)).normalized;
		RaycastHit[] array = Physics.RaycastAll(((Component)main).transform.position, normalized, PushRange, mask);
		if (value)
		{
			PushASA.Instance.mls.LogInfo((object)$"Raycasting for targets: {array.Length} hits found");
		}
		RaycastHit[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			RaycastHit val2 = array2[i];
			ClientPlayerCharacter component2 = ((Component)((RaycastHit)(ref val2)).transform).GetComponent<ClientPlayerCharacter>();
			if (!((Object)(object)component2 != (Object)null) || component2.pv.ViewID == component.pv.ViewID)
			{
				continue;
			}
			Vector3 val3 = normalized * PushForce;
			if ((Object)(object)((Component)component2).GetComponent<PushRPCHandler>() != (Object)null)
			{
				if (value)
				{
					PushASA.Instance.mls.LogInfo((object)$"Pushing player (ViewID: {component2.pv.ViewID}) with force: {val3}");
				}
				component2.pv.RPC("PushPlayerRPC", (RpcTarget)0, new object[4]
				{
					component.pv.ViewID,
					val3.x,
					val3.y,
					val3.z
				});
				lastPushTimes[playerViewId] = Time.time;
				if (component.pv.IsMine && (Object)(object)PlayerLocomotionController.instance != (Object)null)
				{
					PlayerLocomotionController.instance.stamina = Mathf.Clamp01(PlayerLocomotionController.instance.stamina - PushCost);
					if (value)
					{
						PushASA.Instance.mls.LogInfo((object)$"Stamina consumed: {PushCost}, remaining: {PlayerLocomotionController.instance.stamina:F2}");
					}
				}
			}
			else if (value)
			{
				PushASA.Instance.mls.LogWarning((object)$"Target player (ViewID: {component2.pv.ViewID}) does not have PushRPCHandler - they may not have the mod installed!");
			}
			break;
		}
		if (value && array.Length == 0)
		{
			PushASA.Instance.mls.LogInfo((object)"Push failed: No targets in range");
		}
		if (!PushASA.config_DebugPlaySoundAlways.Value || !component.pv.IsMine)
		{
			return;
		}
		PushRPCHandler component3 = ((Component)component).GetComponent<PushRPCHandler>();
		if ((Object)(object)component3 != (Object)null)
		{
			component3.DebugPlayPushSound();
			if (value)
			{
				PushASA.Instance.mls.LogInfo((object)"DEBUG: Playing push sound (no target required)");
			}
		}
	}

	private bool CanPushPlayer(ClientPlayerCharacter player)
	{
		if ((Object)(object)SettingsManager.instance != (Object)null && SettingsManager.instance.inMenu)
		{
			return false;
		}
		if ((Object)(object)PlayerLocomotionController.instance != (Object)null && PlayerLocomotionController.instance.usingTerminal)
		{
			return false;
		}
		if ((Object)(object)PlayerLocomotionController.instance != (Object)null && PlayerLocomotionController.instance.stamina < PushCost)
		{
			return false;
		}
		return true;
	}
}