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