using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using FishNet.Object.Synchronizing;
using HarmonyLib;
using MetaVoiceChat;
using MetaVoiceChat.NetProviders.FishNet;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
[BepInPlugin("com.dan.htf.voicefix", "HTF Voice Fix", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
private static ConfigEntry<int> Complexity;
private static ConfigEntry<int> TrailingSilence;
private static ConfigEntry<int> FishBudget;
private static ConfigEntry<int> MaxKillQueue;
private static ConfigEntry<float> BudgetWindow;
private static ConfigEntry<float> MaxCodecMs;
private static readonly FieldRef<ExplosionInfo, Vector2Int> FishRange = AccessTools.FieldRefAccess<ExplosionInfo, Vector2Int>("_underwaterFishMinMax");
private static float windowStart;
private static int used;
private static readonly List<Creature> spawned = new List<Creature>();
private static float scale;
private static int silent;
private void Awake()
{
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Expected O, but got Unknown
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Expected O, but got Unknown
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Expected O, but got Unknown
//IL_0188: Expected O, but got Unknown
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Expected O, but got Unknown
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Expected O, but got Unknown
Complexity = ((BaseUnityPlugin)this).Config.Bind<int>("Voice", "OpusComplexity", 3, "Opus encoder complexity 0-10 (game default 6). Lower = less CPU.");
MaxCodecMs = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "MaxCodecMs", 100f, "Codec time per frame before the game logs a warning (game default 50).");
TrailingSilence = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "TrailingSilenceFrames", 5, "Empty frames sent after speech stops so peers see you stop talking. Silence is otherwise not sent (game sends 50/s forever).");
FishBudget = ((BaseUnityPlugin)this).Config.Bind<int>("TNT", "FishPerWindow", 30, "Soft cap on fish spawned by underwater explosions per window. Beyond it each explosion spawns 1 fish carrying the value of all the fish it would have spawned.");
BudgetWindow = ((BaseUnityPlugin)this).Config.Bind<float>("TNT", "WindowSeconds", 5f, "Length of the fish budget window.");
MaxKillQueue = ((BaseUnityPlugin)this).Config.Bind<int>("TNT", "MaxKillQueue", 2, "Pending kill-score popups; extra kills are merged into the last one instead of queuing.");
Harmony val = new Harmony("com.dan.htf.voicefix");
val.Patch((MethodBase)AccessTools.Method(typeof(FishNetNetProvider), "MetaVoiceChat.NetProviders.INetProvider.RelayFrame", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "SkipSilence", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)AccessTools.Method(typeof(MetaVc), "StartClient", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "Tune", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)AccessTools.Method(typeof(ExplosionManager), "ServerExplode", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "CapFish", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "RestoreFish", (Type[])null), (HarmonyMethod)null);
val.Patch((MethodBase)AccessTools.Method(typeof(Creature), "ServerKillOnSpawn", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "CountSpawn", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)AccessTools.Method(typeof(PlayerKillScore), "AddKillScore", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Plugin), "MergeKills", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
private static void CapFish(ExplosionInfo info, out Vector2Int __state)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
ref Vector2Int reference = ref FishRange.Invoke(info);
__state = reference;
spawned.Clear();
if (Time.time - windowStart > BudgetWindow.Value)
{
windowStart = Time.time;
used = 0;
}
float num = (float)(((Vector2Int)(ref reference)).x + ((Vector2Int)(ref reference)).y - 1) / 2f;
int num2 = Math.Max(1, Math.Min(((Vector2Int)(ref reference)).y - 1, Math.Max(0, FishBudget.Value - used)));
used += num2;
scale = Math.Max(1f, num / (float)num2);
reference = new Vector2Int(num2, num2 + 1);
}
private static void CountSpawn(Creature __instance)
{
spawned.Add(__instance);
}
private static void RestoreFish(ExplosionInfo info, Vector2Int __state)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
FishRange.Invoke(info) = __state;
if (scale > 1f)
{
foreach (Creature item in spawned)
{
if (Object.op_Implicit((Object)(object)item))
{
SyncVar<float> killScoreMultiplier = ((Item)item)._killScoreMultiplier;
killScoreMultiplier.Value *= scale;
}
}
}
spawned.Clear();
}
private static bool MergeKills(PlayerKillScore __instance, int worth)
{
List<object> list = ((IEnumerable)Traverse.Create((object)__instance).Field("_killScoreQueue").GetValue()).Cast<object>().ToList();
if (list.Count < MaxKillQueue.Value)
{
return true;
}
Traverse val = Traverse.Create(list.Last());
val.Field("Worth").SetValue((object)(val.Field("Worth").GetValue<int>() + worth));
val.Field("Killed").SetValue((object)"many");
return false;
}
private static bool SkipSilence(ReadOnlySpan<byte> data)
{
if (data.Length > 0)
{
silent = 0;
return true;
}
return silent++ < TrailingSilence.Value;
}
private static void Tune(MetaVc __instance)
{
__instance.config.complexity = Complexity.Value;
__instance.maxCodecMilliseconds = MaxCodecMs.Value;
}
}