using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Player;
using SNetwork;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
namespace HawChow.ReviveVoice;
[BepInPlugin("HawChow.ReviveVoice", "ReviveVoice", "1.0.3")]
public sealed class Plugin : BasePlugin
{
private const string HostObjectName = "HawChow.ReviveVoice.Host";
internal static Plugin Instance;
internal static ConfigEntry<bool> Enabled;
internal static ConfigEntry<float> Volume;
internal static ReviveAudioHost Host;
private static GameObject _hostObject;
private static AudioClip _clip;
private static bool _loggedHostRebuild;
private static bool _loggedClipReload;
public override void Load()
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Expected O, but got Unknown
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Expected O, but got Unknown
Instance = this;
Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Play the revive voice on every client that receives the game's replicated revive state.");
Volume = ((BasePlugin)this).Config.Bind<float>("Audio", "Volume", 0.5f, new ConfigDescription("Voice playback volume, from 0.0 to 1.0. Lowered from 0.85 in 1.0.2 because the clip is a loud shout.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
ClassInjector.RegisterTypeInIl2Cpp<ReviveAudioHost>();
Harmony val = new Harmony("HawChow.ReviveVoice");
val.PatchAll(typeof(Plugin).Assembly);
LogPatchReceipt(val, AccessTools.Method(typeof(Interact_Revive), "SyncReviverState", (Type[])null, (Type[])null), "Interact_Revive.SyncReviverState");
LogPatchReceipt(val, AccessTools.Method(typeof(PLOC_Downed), "OnPlayerRevived", (Type[])null, (Type[])null), "PLOC_Downed.OnPlayerRevived");
_clip = ReviveAudioAsset.Load(Assembly.GetExecutingAssembly(), ((BasePlugin)this).Log);
Host = (((Object)(object)_clip != (Object)null) ? CreateHost() : null);
if ((Object)(object)_clip == (Object)null)
{
((BasePlugin)this).Log.LogWarning((object)"Embedded revive voice is unavailable at load; hooks stay installed and the clip is reloaded on the first rescue.");
}
else if ((Object)(object)Host == (Object)null)
{
((BasePlugin)this).Log.LogWarning((object)"Revive audio host could not be created at load; hooks stay installed and the host is rebuilt on the first rescue.");
}
string text = (((Object)(object)_clip != (Object)null) ? $"{_clip.length:0.00}s" : "unavailable");
ManualLogSource log = ((BasePlugin)this).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(103, 6, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("ReviveVoice");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.3");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded; replicated rescue audio enabled=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(Enabled.Value);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; volume=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(Volume.Value, "0.00");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; embedded clip=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; host='");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("HawChow.ReviveVoice.Host");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' pinned across scene loads.");
}
log.LogInfo(val2);
}
internal static ReviveAudioHost EnsureHost()
{
if ((Object)(object)_clip == (Object)null)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
Plugin instance = Instance;
_clip = ReviveAudioAsset.Load(executingAssembly, (instance != null) ? ((BasePlugin)instance).Log : null);
if ((Object)(object)_clip == (Object)null)
{
return null;
}
if (!_loggedClipReload)
{
_loggedClipReload = true;
Plugin instance2 = Instance;
if (instance2 != null)
{
((BasePlugin)instance2).Log.LogWarning((object)"[HOST] embedded revive clip had to be reloaded; rescue audio rearmed.");
}
}
if ((Object)(object)Host != (Object)null)
{
Host.Initialize(_clip);
}
}
if ((Object)(object)Host != (Object)null)
{
return Host;
}
ReviveAudioHost reviveAudioHost = CreateHost();
if ((Object)(object)reviveAudioHost == (Object)null)
{
return null;
}
Host = reviveAudioHost;
if (!_loggedHostRebuild)
{
_loggedHostRebuild = true;
Plugin instance3 = Instance;
if (instance3 != null)
{
((BasePlugin)instance3).Log.LogWarning((object)"[HOST] revive audio host was missing at revive time and has been recreated; rescue audio continues from here.");
}
}
return Host;
}
private static ReviveAudioHost CreateHost()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
try
{
if ((Object)(object)_hostObject == (Object)null)
{
_hostObject = new GameObject("HawChow.ReviveVoice.Host");
((Object)_hostObject).hideFlags = (HideFlags)61;
Object.DontDestroyOnLoad((Object)(object)_hostObject);
}
ReviveAudioHost reviveAudioHost = _hostObject.GetComponent<ReviveAudioHost>();
if ((Object)(object)reviveAudioHost == (Object)null)
{
reviveAudioHost = _hostObject.AddComponent<ReviveAudioHost>();
}
reviveAudioHost.Initialize(_clip);
return reviveAudioHost;
}
catch (Exception ex)
{
Plugin instance = Instance;
if (instance != null)
{
ManualLogSource log = ((BasePlugin)instance).Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Revive audio host creation failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.GetType().Name);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogError(val);
}
return null;
}
}
private void LogPatchReceipt(Harmony harmony, MethodBase target, string label)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
bool flag = default(bool);
if (target == null)
{
ManualLogSource log = ((BasePlugin)this).Log;
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[PATCH] ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(label);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": target missing.");
}
log.LogError(val);
return;
}
Patches patchInfo = Harmony.GetPatchInfo(target);
int num = patchInfo?.Prefixes.Count ?? 0;
int num2 = patchInfo?.Postfixes.Count ?? 0;
ManualLogSource log2 = ((BasePlugin)this).Log;
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(29, 4, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[PATCH] ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(label);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": pre=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(",post=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num2);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; owner=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("HawChow.ReviveVoice");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
}
log2.LogInfo(val2);
}
}
internal static class PluginInfo
{
internal const string Guid = "HawChow.ReviveVoice";
internal const string Name = "ReviveVoice";
internal const string Version = "1.0.3";
}
internal static class ReviveAudioAsset
{
private const string ResourceName = "ReviveVoice.Audio.revive-voice.wav";
internal static AudioClip Load(Assembly assembly, ManualLogSource log)
{
//IL_0239: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Expected O, but got Unknown
try
{
using Stream stream = assembly.GetManifestResourceStream("ReviveVoice.Audio.revive-voice.wav");
if (stream == null)
{
throw new InvalidDataException("Missing resource ReviveVoice.Audio.revive-voice.wav.");
}
using MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
byte[] array = memoryStream.ToArray();
if (array.Length < 12 || Encoding.ASCII.GetString(array, 0, 4) != "RIFF" || Encoding.ASCII.GetString(array, 8, 4) != "WAVE")
{
throw new InvalidDataException("Embedded revive voice has an invalid RIFF/WAVE header.");
}
int num = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
int num5 = -1;
int num6 = 0;
int num7 = 12;
while (num7 <= array.Length - 8)
{
string text = Encoding.ASCII.GetString(array, num7, 4);
int num8 = BitConverter.ToInt32(array, num7 + 4);
int num9 = num7 + 8;
if (num8 < 0 || num9 > array.Length - num8)
{
throw new InvalidDataException("Malformed WAV chunk length.");
}
if (text == "fmt ")
{
if (num8 < 16)
{
throw new InvalidDataException("WAV fmt chunk is incomplete.");
}
num = BitConverter.ToUInt16(array, num9);
num2 = BitConverter.ToUInt16(array, num9 + 2);
num3 = BitConverter.ToInt32(array, num9 + 4);
num4 = BitConverter.ToUInt16(array, num9 + 14);
}
else if (text == "data")
{
num5 = num9;
num6 = num8;
}
long num10 = (long)num9 + (long)num8 + (num8 & 1);
if (num10 > array.Length)
{
throw new InvalidDataException("WAV chunk exceeds the file length.");
}
num7 = (int)num10;
}
if (num != 1 || num2 != 1 || num3 < 8000 || num3 > 48000 || num4 != 16 || num5 < 0 || num6 <= 0 || (num6 & 1) != 0)
{
throw new InvalidDataException("Revive voice must be mono PCM16 at 8–48 kHz.");
}
int num11 = num6 / 2;
float[] array2 = new float[num11];
for (int i = 0; i < num11; i++)
{
int num12 = num5 + i * 2;
short num13 = (short)(array[num12] | (array[num12 + 1] << 8));
array2[i] = (float)num13 / 32768f;
}
AudioClip val = AudioClip.Create("ReviveVoice", num11, num2, num3, false);
if ((Object)(object)val == (Object)null || !val.SetData(new Il2CppStructArray<float>(array2), 0))
{
throw new InvalidOperationException("Unity failed to create the revive voice AudioClip.");
}
return val;
}
catch (Exception ex)
{
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(37, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Revive voice resource load failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
log.LogError(val2);
return null;
}
}
}
public sealed class ReviveAudioHost : MonoBehaviour
{
private struct FinishedClip
{
internal ulong Target;
internal AudioSource Source;
}
private const double StopGraceSeconds = 0.35;
private readonly RevivePlaybackLedger _ledger = new RevivePlaybackLedger();
private readonly Dictionary<ulong, AudioSource> _active = new Dictionary<ulong, AudioSource>();
private readonly Dictionary<ulong, double> _pendingStop = new Dictionary<ulong, double>();
private readonly List<FinishedClip> _finishing = new List<FinishedClip>();
private AudioClip _clip;
private bool _warnedPlayback;
public ReviveAudioHost(IntPtr pointer)
: base(pointer)
{
}
internal void Initialize(AudioClip clip)
{
_clip = clip;
}
internal void Begin(ulong target, ulong reviver, string targetName, string reviverName)
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
PlaybackTransition transition = _ledger.Begin(target, reviver, Time.realtimeSinceStartup);
if (transition.Command != PlaybackCommand.None)
{
_pendingStop.Remove(target);
}
Apply(transition);
if (transition.Command == PlaybackCommand.Start || transition.Command == PlaybackCommand.Restart)
{
ManualLogSource log = ((BasePlugin)Plugin.Instance).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(53, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[REVIVE] started; reviver=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reviverName);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; target=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(targetName);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; replicated=true.");
}
log.LogInfo(val);
}
}
internal void Release(ulong target, ulong reviver, bool targetIsAlive)
{
PlaybackTransition transition = _ledger.Release(target, reviver, targetIsAlive);
if (transition.Command != PlaybackCommand.Stop)
{
Apply(transition);
}
else
{
_pendingStop[target] = (double)Time.realtimeSinceStartup + 0.35;
}
}
internal void Complete(ulong target)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Expected O, but got Unknown
_pendingStop.Remove(target);
PlaybackTransition transition = _ledger.Complete(target);
Apply(transition);
if (transition.Command == PlaybackCommand.Complete)
{
ManualLogSource log = ((BasePlugin)Plugin.Instance).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(59, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[REVIVE] success; targetLookup=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(target);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; audio=finish-current-clip.");
}
log.LogInfo(val);
}
}
private void Update()
{
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Expected O, but got Unknown
try
{
double now = Time.realtimeSinceStartup;
List<PlaybackTransition> list = _ledger.Expire(now);
for (int i = 0; i < list.Count; i++)
{
Apply(list[i]);
}
FlushPendingStops(now);
for (int num = _finishing.Count - 1; num >= 0; num--)
{
AudioSource source = _finishing[num].Source;
if (!((Object)(object)source != (Object)null) || !source.isPlaying)
{
DestroySource(source);
_finishing.RemoveAt(num);
}
}
if (Plugin.Enabled != null && !Plugin.Enabled.Value)
{
StopActiveSessions();
}
}
catch (Exception ex)
{
if (_warnedPlayback)
{
return;
}
_warnedPlayback = true;
Plugin instance = Plugin.Instance;
if (instance != null)
{
ManualLogSource log = ((BasePlugin)instance).Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(30, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Revive audio update failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.GetType().Name);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogError(val);
}
}
}
private void Apply(PlaybackTransition transition)
{
switch (transition.Command)
{
case PlaybackCommand.None:
break;
case PlaybackCommand.Start:
StartSource(transition.Target);
break;
case PlaybackCommand.Restart:
StopSource(transition.Target);
StartSource(transition.Target);
break;
case PlaybackCommand.Stop:
StopSource(transition.Target);
break;
case PlaybackCommand.Complete:
{
if (_active.TryGetValue(transition.Target, out var value))
{
_active.Remove(transition.Target);
_finishing.Add(new FinishedClip
{
Target = transition.Target,
Source = value
});
}
break;
}
}
}
private void FlushPendingStops(double now)
{
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Expected O, but got Unknown
if (_pendingStop.Count == 0)
{
return;
}
List<ulong> list = null;
foreach (KeyValuePair<ulong, double> item in _pendingStop)
{
if (!(now < item.Value))
{
if (list == null)
{
list = new List<ulong>();
}
list.Add(item.Key);
}
}
if (list == null)
{
return;
}
bool flag = default(bool);
for (int i = 0; i < list.Count; i++)
{
_pendingStop.Remove(list[i]);
StopSource(list[i]);
Plugin instance = Plugin.Instance;
if (instance != null)
{
ManualLogSource log = ((BasePlugin)instance).Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(51, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[REVIVE] interrupted; targetLookup=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ulong>(list[i]);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; audio=stopped.");
}
log.LogInfo(val);
}
}
}
private void StartSource(ulong target)
{
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Expected O, but got Unknown
if ((Object)(object)_clip == (Object)null)
{
if (!_warnedPlayback)
{
_warnedPlayback = true;
Plugin instance = Plugin.Instance;
if (instance != null)
{
((BasePlugin)instance).Log.LogError((object)"Revive voice playback skipped: this host has no embedded clip.");
}
}
return;
}
try
{
StopFinishingFor(target);
AudioSource val = ((Component)this).gameObject.AddComponent<AudioSource>();
val.playOnAwake = false;
val.loop = false;
val.spatialBlend = 0f;
val.volume = Mathf.Clamp01((Plugin.Volume != null) ? Plugin.Volume.Value : 0.5f);
val.clip = _clip;
val.Play();
_active[target] = val;
}
catch (Exception ex)
{
if (_warnedPlayback)
{
return;
}
_warnedPlayback = true;
Plugin instance2 = Plugin.Instance;
if (instance2 != null)
{
ManualLogSource log = ((BasePlugin)instance2).Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(32, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Revive voice playback failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
log.LogError(val2);
}
}
}
private void StopSource(ulong target)
{
if (_active.TryGetValue(target, out var value))
{
_active.Remove(target);
DestroySource(value);
}
}
private void StopFinishingFor(ulong target)
{
for (int num = _finishing.Count - 1; num >= 0; num--)
{
if (_finishing[num].Target == target)
{
DestroySource(_finishing[num].Source);
_finishing.RemoveAt(num);
}
}
}
private static void DestroySource(AudioSource source)
{
if ((Object)(object)source == (Object)null)
{
return;
}
try
{
source.Stop();
Object.Destroy((Object)(object)source);
}
catch
{
}
}
private void StopActiveSessions()
{
_pendingStop.Clear();
List<PlaybackTransition> list = _ledger.Clear();
for (int i = 0; i < list.Count; i++)
{
Apply(list[i]);
}
}
private void OnDestroy()
{
_pendingStop.Clear();
StopActiveSessions();
for (int i = 0; i < _finishing.Count; i++)
{
DestroySource(_finishing[i].Source);
}
_finishing.Clear();
_clip = null;
}
}
internal static class RevivePatchTargets
{
internal static IEnumerable<MethodBase> Methods(Type type, string name)
{
MethodBase methodBase = AccessTools.Method(type, name, (Type[])null, (Type[])null);
if (methodBase == null)
{
throw new MissingMethodException(type.FullName, name);
}
yield return methodBase;
}
}
[HarmonyPatch]
internal static class ReviveStatePatch
{
private const int UnresolvedWarnLimit = 5;
private static int _unresolvedWarns;
private static IEnumerable<MethodBase> TargetMethods()
{
return RevivePatchTargets.Methods(typeof(Interact_Revive), "SyncReviverState");
}
[HarmonyPostfix]
private static void Postfix(pPlayerReviveState __0)
{
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Expected O, but got Unknown
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
bool flag3 = default(bool);
try
{
if (Plugin.Enabled == null || !Plugin.Enabled.Value)
{
return;
}
ReviveAudioHost reviveAudioHost = Plugin.EnsureHost();
if ((Object)(object)reviveAudioHost == (Object)null)
{
return;
}
PlayerAgent val = default(PlayerAgent);
bool flag = ((pPlayerAgent)(ref __0.TargetPlayer)).TryGet(ref val) && (Object)(object)val != (Object)null && (Object)(object)val.Owner != (Object)null;
PlayerAgent val2 = default(PlayerAgent);
bool flag2 = ((pPlayerAgent)(ref __0.SourcePlayer)).TryGet(ref val2) && (Object)(object)val2 != (Object)null && (Object)(object)val2.Owner != (Object)null;
if (!flag || !flag2)
{
if (_unresolvedWarns >= 5)
{
return;
}
_unresolvedWarns++;
Plugin instance = Plugin.Instance;
if (instance != null)
{
ManualLogSource log = ((BasePlugin)instance).Log;
BepInExWarningLogInterpolatedStringHandler val3 = new BepInExWarningLogInterpolatedStringHandler(155, 4, ref flag3);
if (flag3)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[DIAG] revive state could not resolve its players (target=");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(flag);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", reviver=");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(flag2);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", active=");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(__0.State);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("); rescue audio skipped for that packet; diagnostics stop after ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(5);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" such packets.");
}
log.LogWarning(val3);
}
}
else
{
ulong lookup = val.Owner.Lookup;
ulong lookup2 = val2.Owner.Lookup;
if (__0.State)
{
reviveAudioHost.Begin(lookup, lookup2, val.Owner.GetName(), val2.Owner.GetName());
}
else
{
reviveAudioHost.Release(lookup, lookup2, val.m_alive);
}
}
}
catch (Exception ex)
{
Plugin instance = Plugin.Instance;
if (instance != null)
{
ManualLogSource log2 = ((BasePlugin)instance).Log;
BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(35, 2, ref flag3);
if (flag3)
{
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Revive state observation failed: ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(ex.GetType().Name);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(ex.Message);
}
log2.LogError(val4);
}
}
}
}
[HarmonyPatch]
internal static class ReviveCompletionPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return RevivePatchTargets.Methods(typeof(PLOC_Downed), "OnPlayerRevived");
}
[HarmonyPostfix]
private static void Postfix(PLOC_Downed __instance)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
try
{
if (Plugin.Enabled == null || !Plugin.Enabled.Value)
{
return;
}
ReviveAudioHost reviveAudioHost = Plugin.EnsureHost();
if (!((Object)(object)reviveAudioHost == (Object)null))
{
SNet_Player val = ((__instance != null && (Object)(object)((PLOC_Base)__instance).m_owner != (Object)null) ? ((PLOC_Base)__instance).m_owner.Owner : null);
if ((Object)(object)val != (Object)null)
{
reviveAudioHost.Complete(val.Lookup);
}
}
}
catch (Exception ex)
{
Plugin instance = Plugin.Instance;
if (instance != null)
{
ManualLogSource log = ((BasePlugin)instance).Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(40, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Revive completion observation failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
log.LogError(val2);
}
}
}
}
internal enum PlaybackCommand
{
None,
Start,
Restart,
Stop,
Complete
}
internal readonly struct PlaybackTransition
{
internal PlaybackCommand Command { get; }
internal ulong Target { get; }
internal ulong Reviver { get; }
internal ulong PreviousReviver { get; }
internal static PlaybackTransition None => new PlaybackTransition(PlaybackCommand.None, 0uL, 0uL, 0uL);
internal PlaybackTransition(PlaybackCommand command, ulong target, ulong reviver, ulong previousReviver = 0uL)
{
Command = command;
Target = target;
Reviver = reviver;
PreviousReviver = previousReviver;
}
}
internal sealed class RevivePlaybackLedger
{
private struct Session
{
internal ulong Reviver;
internal double ExpiresAt;
}
internal const double ActiveTimeoutSeconds = 20.0;
private readonly Dictionary<ulong, Session> _sessions = new Dictionary<ulong, Session>();
internal int Count => _sessions.Count;
internal PlaybackTransition Begin(ulong target, ulong reviver, double now)
{
if (target == 0L || reviver == 0L || target == reviver || !double.IsFinite(now))
{
return PlaybackTransition.None;
}
if (_sessions.TryGetValue(target, out var value))
{
if (value.Reviver == reviver)
{
value.ExpiresAt = now + 20.0;
_sessions[target] = value;
return PlaybackTransition.None;
}
_sessions[target] = new Session
{
Reviver = reviver,
ExpiresAt = now + 20.0
};
return new PlaybackTransition(PlaybackCommand.Restart, target, reviver, value.Reviver);
}
_sessions.Add(target, new Session
{
Reviver = reviver,
ExpiresAt = now + 20.0
});
return new PlaybackTransition(PlaybackCommand.Start, target, reviver, 0uL);
}
internal PlaybackTransition Release(ulong target, ulong reviver, bool targetIsAlive)
{
if (target == 0L || reviver == 0L || !_sessions.TryGetValue(target, out var value) || value.Reviver != reviver)
{
return PlaybackTransition.None;
}
_sessions.Remove(target);
return new PlaybackTransition(targetIsAlive ? PlaybackCommand.Complete : PlaybackCommand.Stop, target, reviver, 0uL);
}
internal PlaybackTransition Complete(ulong target)
{
if (target == 0L || !_sessions.TryGetValue(target, out var value))
{
return PlaybackTransition.None;
}
_sessions.Remove(target);
return new PlaybackTransition(PlaybackCommand.Complete, target, value.Reviver, 0uL);
}
internal List<PlaybackTransition> Expire(double now)
{
List<PlaybackTransition> list = new List<PlaybackTransition>();
if (!double.IsFinite(now))
{
return list;
}
List<ulong> list2 = new List<ulong>();
foreach (KeyValuePair<ulong, Session> session in _sessions)
{
if (!(now <= session.Value.ExpiresAt))
{
list2.Add(session.Key);
list.Add(new PlaybackTransition(PlaybackCommand.Stop, session.Key, session.Value.Reviver, 0uL));
}
}
for (int i = 0; i < list2.Count; i++)
{
_sessions.Remove(list2[i]);
}
return list;
}
internal List<PlaybackTransition> Clear()
{
List<PlaybackTransition> list = new List<PlaybackTransition>(_sessions.Count);
foreach (KeyValuePair<ulong, Session> session in _sessions)
{
list.Add(new PlaybackTransition(PlaybackCommand.Stop, session.Key, session.Value.Reviver, 0uL));
}
_sessions.Clear();
return list;
}
}