using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Marioalexsan.PerfectGuard.Patches;
using Marioalexsan.PerfectGuard.SoftDependencies;
using Microsoft.CodeAnalysis;
using Mirror;
using Mirror.RemoteCalls;
using Nessie.ATLYSS.EasySettings;
using Nessie.ATLYSS.EasySettings.UIElements;
using UnityEngine;
using UnityEngine.Events;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Mirror")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Marioalexsan.PerfectGuard")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+dfed091d3d87b00e40690fc3ce3b908627b46efa")]
[assembly: AssemblyProduct("PerfectGuard")]
[assembly: AssemblyTitle("Marioalexsan.PerfectGuard")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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;
}
}
}
namespace Marioalexsan.PerfectGuard
{
public enum SuspicionLevel
{
Normal,
Suspicious,
Confirmed
}
internal class AbuseDetectorEMA
{
private struct TrackedData
{
public DateTime TimeSinceLastEvent;
public TimeSpan TimeBetweenEventsEMA;
public SuspicionLevel Suspicion;
}
private readonly Dictionary<NetworkBehaviour, TrackedData> PlayerData = new Dictionary<NetworkBehaviour, TrackedData>();
public static List<AbuseDetectorEMA> AllDetectors { get; } = new List<AbuseDetectorEMA>();
public double SupicionRate { get; }
public double ConfirmRate { get; }
public double Factor { get; } = 0.3;
public TimeSpan SuspicionTimeBetweenEvents { get; }
public TimeSpan ConfirmTimeBetweenEvents { get; }
public SuspicionLevel Suspicion { get; private set; } = SuspicionLevel.Normal;
public event EventHandler<NetworkBehaviour>? OnSuspicionRaised;
public event EventHandler<NetworkBehaviour>? OnConfirmRaised;
public static void RunActorCleanup()
{
for (int i = 0; i < AllDetectors.Count; i++)
{
Dictionary<NetworkBehaviour, TrackedData> playerData = AllDetectors[i].PlayerData;
KeyValuePair<NetworkBehaviour, TrackedData>[] array = playerData.ToArray();
for (int j = 0; j < array.Length; j++)
{
KeyValuePair<NetworkBehaviour, TrackedData> keyValuePair = array[j];
if (!Object.op_Implicit((Object)(object)keyValuePair.Key))
{
playerData.Remove(keyValuePair.Key);
}
}
}
}
public AbuseDetectorEMA(double suspicionRate)
: this(suspicionRate, suspicionRate * 4.0)
{
}
public AbuseDetectorEMA(double suspicionRate, double confirmRate)
{
SupicionRate = suspicionRate;
ConfirmRate = Math.Max(confirmRate, suspicionRate);
SuspicionTimeBetweenEvents = TimeSpan.FromSeconds(1.0 / SupicionRate);
ConfirmTimeBetweenEvents = TimeSpan.FromSeconds(1.0 / ConfirmRate);
AllDetectors.Add(this);
}
public void TrackEvent(NetworkBehaviour player)
{
DateTime now = DateTime.Now;
if (!PlayerData.TryGetValue(player, out var value))
{
PlayerData[player] = new TrackedData
{
TimeSinceLastEvent = now,
TimeBetweenEventsEMA = SuspicionTimeBetweenEvents * 2.0,
Suspicion = SuspicionLevel.Normal
};
return;
}
TimeSpan timeSpan = now - value.TimeSinceLastEvent;
TimeSpan timeSpan2 = Factor * timeSpan + (1.0 - Factor) * value.TimeBetweenEventsEMA;
value.TimeSinceLastEvent = now;
value.TimeBetweenEventsEMA = timeSpan2;
SuspicionLevel suspicionLevel = SuspicionLevel.Normal;
if (timeSpan2 <= ConfirmTimeBetweenEvents)
{
suspicionLevel = SuspicionLevel.Confirmed;
if (suspicionLevel > value.Suspicion)
{
this.OnConfirmRaised?.Invoke(this, player);
}
}
else if (timeSpan2 <= SuspicionTimeBetweenEvents)
{
suspicionLevel = SuspicionLevel.Suspicious;
if (suspicionLevel > value.Suspicion)
{
this.OnSuspicionRaised?.Invoke(this, player);
}
}
Dictionary<NetworkBehaviour, TrackedData> playerData = PlayerData;
TrackedData value2 = value;
value2.Suspicion = suspicionLevel;
playerData[player] = value2;
Suspicion = suspicionLevel;
}
}
internal class AbuseDetectorTokenBucket
{
public struct RateLimitData
{
public bool IsRateLimited;
public DateTime PreviousRateLimitAt;
}
private struct TrackedData
{
public DateTime LastEventTime;
public DateTime LastRateLimitedTime;
public double Tokens;
}
private readonly Dictionary<NetworkBehaviour, TrackedData> PlayerData = new Dictionary<NetworkBehaviour, TrackedData>();
public static List<AbuseDetectorTokenBucket> AllDetectors { get; } = new List<AbuseDetectorTokenBucket>();
public double RateLimit { get; }
public double BurstLimit { get; }
public static void RunActorCleanup()
{
for (int i = 0; i < AllDetectors.Count; i++)
{
Dictionary<NetworkBehaviour, TrackedData> playerData = AllDetectors[i].PlayerData;
KeyValuePair<NetworkBehaviour, TrackedData>[] array = playerData.ToArray();
for (int j = 0; j < array.Length; j++)
{
KeyValuePair<NetworkBehaviour, TrackedData> keyValuePair = array[j];
if (!Object.op_Implicit((Object)(object)keyValuePair.Key))
{
playerData.Remove(keyValuePair.Key);
}
}
}
}
public AbuseDetectorTokenBucket(double rateLimit)
: this(rateLimit, rateLimit * 4.0)
{
}
public AbuseDetectorTokenBucket(double rateLimit, double burstLimit)
{
RateLimit = rateLimit;
BurstLimit = Math.Max(burstLimit, rateLimit);
if (burstLimit <= rateLimit)
{
Logging.LogWarning("A token bucket configuration is incorrect!");
}
AllDetectors.Add(this);
}
public RateLimitData TrackEvent(NetworkBehaviour player)
{
DateTime now = DateTime.Now;
if (!PlayerData.TryGetValue(player, out var value))
{
value = (PlayerData[player] = new TrackedData
{
LastEventTime = now,
LastRateLimitedTime = DateTime.UnixEpoch,
Tokens = BurstLimit
});
}
double num = Math.Max((now - value.LastEventTime).TotalSeconds, 0.0);
value.LastEventTime = now;
value.Tokens = Math.Clamp(value.Tokens + RateLimit * num, 0.0, BurstLimit);
bool isRateLimited = true;
DateTime lastRateLimitedTime = value.LastRateLimitedTime;
if (value.Tokens >= 1.0)
{
value.Tokens -= 1.0;
isRateLimited = false;
}
else
{
value.LastRateLimitedTime = now;
}
PlayerData[player] = value;
RateLimitData result = default(RateLimitData);
result.IsRateLimited = isRateLimited;
result.PreviousRateLimitAt = lastRateLimitedTime;
return result;
}
}
internal static class Logging
{
private static ManualLogSource InternalLogger => PerfectGuard.Plugin.Logger;
public static void LogFatal(object data, ConfigEntry<bool>? toggle = null)
{
Log(data, (LogLevel)1, toggle);
}
public static void LogError(object data, ConfigEntry<bool>? toggle = null)
{
Log(data, (LogLevel)2, toggle);
}
public static void LogWarning(object data, ConfigEntry<bool>? toggle = null)
{
Log(data, (LogLevel)4, toggle);
}
public static void LogMessage(object data, ConfigEntry<bool>? toggle = null)
{
Log(data, (LogLevel)8, toggle);
}
public static void LogInfo(object data, ConfigEntry<bool>? toggle = null)
{
Log(data, (LogLevel)16, toggle);
}
public static void LogDebug(object data, ConfigEntry<bool>? toggle = null)
{
Log(data, (LogLevel)32, toggle);
}
private static void Log(object data, LogLevel level = 16, ConfigEntry<bool>? toggle = null)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
if (toggle == null || toggle.Value)
{
ManualLogSource internalLogger = InternalLogger;
if (internalLogger != null)
{
internalLogger.Log(level, data);
}
}
}
}
public class NetItemObjectTracker : NetworkBehaviour
{
public static readonly List<Net_ItemObject> Items = new List<Net_ItemObject>();
private Net_ItemObject _itemObject = null;
public void Awake()
{
_itemObject = ((Component)this).GetComponent<Net_ItemObject>();
Items.Add(_itemObject);
}
public void OnDestroy()
{
Items.Remove(_itemObject);
}
}
[BepInPlugin("Marioalexsan.PerfectGuard", "PerfectGuard", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class PerfectGuard : BaseUnityPlugin
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static UnityAction <>9__33_0;
internal void <Awake>b__33_0()
{
EasySettings.AddHeader("PerfectGuard");
EasySettings.AddToggle("Enable PerfectGuard (recommended)", EnablePerfectGuard);
EasySettings.AddToggle("Detailed logging", DetailedLogging);
EasySettings.AddToggle("Network rate limits (recommended)", NetworkRateLimiting);
EasySettings.AddToggle("Audio rate limits", AudioRateLimiting);
EasySettings.AddToggle("Enable item cleanup", ItemCleanup);
EasySettings.AddSlider("Item cleanup max items", MaxItemsThreshold, wholeNumbers: true);
}
}
private static PerfectGuard? _plugin;
private readonly Harmony _harmony = new Harmony("Marioalexsan.PerfectGuard");
private static ConfigEntry<bool> EnablePerfectGuard;
private static ConfigEntry<bool> NetworkRateLimiting;
private static ConfigEntry<bool> ItemCleanup;
private static ConfigEntry<bool> AudioRateLimiting;
private static ConfigEntry<float> MaxItemsThreshold;
private TimeSpan _abuseDetectorCleanupAccumulator;
private TimeSpan _miscAccumulator;
public static PerfectGuard Plugin => _plugin ?? throw new InvalidOperationException("PerfectGuard hasn't been initialized yet. Either wait until initialization, or check via ChainLoader instead.");
internal ManualLogSource Logger { get; private set; }
public static ConfigEntry<bool> DetailedLogging { get; private set; }
public static bool NetworkRateLimitingEnabled { get; private set; }
public static bool AudioRateLimitingEnabled { get; private set; }
public static bool ItemCleanupEnabled { get; private set; }
public PerfectGuard()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Expected O, but got Unknown
_plugin = this;
Logger = ((BaseUnityPlugin)this).Logger;
EnablePerfectGuard = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnablePerfectGuard", true, "Enable or disable all features of this mod.");
DetailedLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DetailedLogging", true, "Log detailed warnings for detected malicious activities.");
NetworkRateLimiting = ((BaseUnityPlugin)this).Config.Bind<bool>("Protections", "NetworkRateLimiting", true, "Enables rate limits for network spam, such as visual effects and other abuse.");
AudioRateLimiting = ((BaseUnityPlugin)this).Config.Bind<bool>("Protections", "AudioRateLimiting", true, "Enables audio rate limits to prevent spam.");
ItemCleanup = ((BaseUnityPlugin)this).Config.Bind<bool>("Protections", "ItemCleanup", true, "Enable cleanup for excessive item drops.");
MaxItemsThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Tuning", "MaxItemsThreshold", 200f, new ConfigDescription("The maximum number of items allowed before the items are forcefully cleaned up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 500f), Array.Empty<object>()));
UpdateEnableValues();
}
private static void UpdateEnableValues()
{
NetworkRateLimitingEnabled = EnablePerfectGuard.Value && NetworkRateLimiting.Value;
AudioRateLimitingEnabled = EnablePerfectGuard.Value && AudioRateLimiting.Value;
ItemCleanupEnabled = EnablePerfectGuard.Value && ItemCleanup.Value;
}
public void Awake()
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
_harmony.PatchAll();
if (!EasySettings.IsAvailable)
{
return;
}
UnityEvent onInitialized = EasySettings.OnInitialized;
object obj = <>c.<>9__33_0;
if (obj == null)
{
UnityAction val = delegate
{
EasySettings.AddHeader("PerfectGuard");
EasySettings.AddToggle("Enable PerfectGuard (recommended)", EnablePerfectGuard);
EasySettings.AddToggle("Detailed logging", DetailedLogging);
EasySettings.AddToggle("Network rate limits (recommended)", NetworkRateLimiting);
EasySettings.AddToggle("Audio rate limits", AudioRateLimiting);
EasySettings.AddToggle("Enable item cleanup", ItemCleanup);
EasySettings.AddSlider("Item cleanup max items", MaxItemsThreshold, wholeNumbers: true);
};
<>c.<>9__33_0 = val;
obj = (object)val;
}
onInitialized.AddListener((UnityAction)obj);
EasySettings.OnApplySettings.AddListener((UnityAction)delegate
{
try
{
((BaseUnityPlugin)this).Config.Save();
UpdateEnableValues();
}
catch (Exception ex)
{
Logging.LogError("PefectGuard crashed in OnApplySettings! Please report this error to the mod developer:");
Logging.LogError(ex.ToString());
}
});
}
public void Update()
{
CheckForObjectSpikes();
CheckAbuseDetectorCleanup();
CheckAudioCleanup();
}
private void CheckAbuseDetectorCleanup()
{
_abuseDetectorCleanupAccumulator += TimeSpan.FromSeconds(Time.deltaTime);
if (_abuseDetectorCleanupAccumulator >= TimeSpan.FromSeconds(60.0))
{
_abuseDetectorCleanupAccumulator = TimeSpan.Zero;
AbuseDetectorEMA.RunActorCleanup();
AbuseDetectorTokenBucket.RunActorCleanup();
}
}
private void CheckAudioCleanup()
{
_miscAccumulator += TimeSpan.FromSeconds(Time.deltaTime);
if (_miscAccumulator >= TimeSpan.FromSeconds(2.0))
{
_abuseDetectorCleanupAccumulator = TimeSpan.Zero;
PreventAudioSpam.CleanupDeadAudioSources();
}
}
private void CheckForObjectSpikes()
{
if (!ItemCleanupEnabled || !NetworkServer.active || !((float)NetItemObjectTracker.Items.Count > MaxItemsThreshold.Value))
{
return;
}
Logging.LogWarning($"Current item count is above the allowed limit ({MaxItemsThreshold.Value})! Cleaning up excessive items...", DetailedLogging);
List<Net_ItemObject> items = NetItemObjectTracker.Items;
int num = items.Count * 85 / 100;
int num2;
Renderer val2 = default(Renderer);
Collider val3 = default(Collider);
for (num2 = 0; num2 < num; num2++)
{
Net_ItemObject val = items[num2];
if (((Component)val).TryGetComponent<Renderer>(ref val2))
{
val2.enabled = false;
}
if (((Component)val).TryGetComponent<Collider>(ref val3))
{
val3.enabled = false;
}
if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val._itemObj))
{
val._itemObj.UnspawnObject();
}
items.RemoveAt(num2);
num2--;
num--;
}
}
}
internal static class ModInfo
{
public const string GUID = "Marioalexsan.PerfectGuard";
public const string NAME = "PerfectGuard";
public const string VERSION = "1.1.0";
}
}
namespace Marioalexsan.PerfectGuard.SoftDependencies
{
public static class EasySettings
{
private const MethodImplOptions SoftDepend = MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization;
public const string ModID = "EasySettings";
public static readonly Version ExpectedVersion = new Version("1.2.0");
private static BaseUnityPlugin? _plugin;
private static bool _initialized;
public static bool IsAvailable
{
get
{
if (!_initialized)
{
_plugin = (Chainloader.PluginInfos.TryGetValue("EasySettings", out var value) ? value.Instance : null);
_initialized = true;
if ((Object)(object)_plugin == (Object)null)
{
Logging.LogWarning("Soft dependency EasySettings was not found.");
}
else if (_plugin.Info.Metadata.Version != ExpectedVersion)
{
Logging.LogWarning(string.Format("Soft dependency {0} has a different version than expected (have: {1}, expect: {2}).", "EasySettings", _plugin.Info.Metadata.Version, ExpectedVersion));
}
}
return (Object)(object)_plugin != (Object)null;
}
}
public static UnityEvent OnInitialized
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
get
{
return Settings.OnInitialized;
}
}
public static UnityEvent OnCancelSettings
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
get
{
return Settings.OnCancelSettings;
}
}
public static UnityEvent OnApplySettings
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
get
{
return Settings.OnApplySettings;
}
}
public static UnityEvent OnCloseSettings
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
get
{
return Settings.OnCloseSettings;
}
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddSpace()
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddSpace()).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddHeader(string label)
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddHeader(label)).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddButton(string buttonLabel, UnityAction onClick)
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddButton(buttonLabel, onClick)).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddToggle(string label, ConfigEntry<bool> config)
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddToggle(label, config)).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddSlider(string label, ConfigEntry<float> config, bool wholeNumbers = false)
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddSlider(label, config, wholeNumbers)).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddAdvancedSlider(string label, ConfigEntry<float> config, bool wholeNumbers = false)
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddAdvancedSlider(label, config, wholeNumbers)).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddDropdown<T>(string label, ConfigEntry<T> config) where T : Enum
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddDropdown<T>(label, config)).Root).gameObject;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static GameObject AddKeyButton(string label, ConfigEntry<KeyCode> config)
{
return ((Component)((BaseAtlyssElement)Settings.ModTab.AddKeyButton(label, config)).Root).gameObject;
}
}
}
namespace Marioalexsan.PerfectGuard.Patches
{
[HarmonyPatch]
internal static class CmdRpcThrottle
{
private struct ThrottleData
{
public int Limit;
public string MethodName;
public ushort FunctionHash;
}
private const int Unlimited = 16000;
private const int DefaultLimit = 400;
private const int UnspecifiedDefaultLimit = 40;
private const int VeryHighLimit = 400;
private const int HighLimit = 100;
private const int MediumLimit = 40;
private const int LowLimit = 10;
private const int VeryLowLimit = 10;
private static readonly Regex NameRegex;
private static readonly Dictionary<ushort, ThrottleData> CustomRateLimits;
private static readonly ConcurrentDictionary<ushort, AbuseDetectorTokenBucket> Detectors;
static CmdRpcThrottle()
{
NameRegex = new Regex("::([^\\(]*)\\(");
CustomRateLimits = new Dictionary<ushort, ThrottleData>();
Detectors = new ConcurrentDictionary<ushort, AbuseDetectorTokenBucket>();
Throttle("System.Void Mirror.NetworkTransformUnreliable::CmdClientToServerSync(System.Nullable`1<UnityEngine.Vector3>,System.Nullable`1<UnityEngine.Quaternion>,System.Nullable`1<UnityEngine.Vector3>)", 16000);
Throttle("System.Void Mirror.NetworkTransformUnreliable::RpcServerToClientSync(System.Nullable`1<UnityEngine.Vector3>,System.Nullable`1<UnityEngine.Quaternion>,System.Nullable`1<UnityEngine.Vector3>)", 16000);
Throttle("System.Void BreakableObject::Rpc_Break(UnityEngine.Vector3)");
Throttle("System.Void ChatBehaviour::Cmd_SetChatChannel(System.String)");
Throttle("System.Void ChatBehaviour::Cmd_JoinChatRoom(System.String)");
Throttle("System.Void ChatBehaviour::Cmd_ToggleChatBubble(System.Boolean)");
Throttle("System.Void ChatBehaviour::Cmd_SendChatMessage(System.String,ChatBehaviour/ChatChannel)");
Throttle("System.Void ChatBehaviour::Rpc_RecieveChatMessage(System.String,System.Boolean,ChatBehaviour/ChatChannel)");
Throttle("System.Void ChatBehaviour::Target_RecieveMessage(System.String)");
Throttle("System.Void ChatBehaviour::Target_GameLogicMessage(System.String)");
Throttle("System.Void ChatBehaviour::Target_RecieveTriggerMessage(System.String)");
Throttle("System.Void Creep::Rpc_PlayCreepJumpEffect()");
Throttle("System.Void Creep::Rpc_PlayAggroIcon(System.Int32)");
Throttle("System.Void Creep::Rpc_OnCreepSpawn()");
Throttle("System.Void Creep::Rpc_PlayCreepHurtEffect()");
Throttle("System.Void Creep::Rpc_InitCreepDeathParams(System.Boolean)");
Throttle("System.Void Creep::Rpc_TintRender(UnityEngine.Color)");
Throttle("System.Void Creep::Rpc_InitSkillChargeEffect(System.String,System.Single)");
Throttle("System.Void Creep::Rpc_InitSkillCastEffect(System.String)");
Throttle("System.Void Creep::Rpc_CrossFadeAnim(System.String,System.Single,System.Int32)");
Throttle("System.Void Creep::Rpc_CrossFadeAnim_Timed(System.String,System.Single,System.Int32,System.Single)");
Throttle("System.Void Creep::Rpc_InitUnspawnEffect(UnityEngine.Vector3,System.Single)");
Throttle("System.Void CreepSpawner::Rpc_InitSpecialSpawnEffect(UnityEngine.Vector3)");
Throttle("System.Void Net_ItemObject::Rpc_NetItemObjectPickup(Mirror.NetworkIdentity)");
Throttle("System.Void Net_ItemObject::Rpc_SpawnPuffcloud()");
Throttle("System.Void NetNPC::Rpc_CrossFade_Anim(System.String,System.Single,System.Int32)");
Throttle("System.Void Player::Cmd_SetLatency(System.Int32)");
Throttle("System.Void Player::Cmd_InitAfkCondition(System.Boolean)");
Throttle("System.Void Player::Cmd_SetInactive()");
Throttle("System.Void Player::Cmd_Respawn()");
Throttle("System.Void Player::Cmd_ReturnToRecalledInstance()");
Throttle("System.Void Player::Cmd_SceneTransport(System.String,System.String,ZoneDifficulty)");
Throttle("System.Void Player::Cmd_InviteToParty(Player)");
Throttle("System.Void Player::Cmd_LeaveParty()");
Throttle("System.Void Player::Cmd_SetPartyInviteCondition(PartyInviteStatus)");
Throttle("System.Void Player::Target_ResetCameraPositioning()");
Throttle("System.Void PlayerCasting::Cmd_QuerySkillStructs(SkillStruct[])");
Throttle("System.Void PlayerCasting::Cmd_InitSkill(System.String)");
Throttle("System.Void PlayerCasting::Cmd_SpawnEarlySkillObj()");
Throttle("System.Void PlayerCasting::Cmd_InitCastInterrupt()");
Throttle("System.Void PlayerCasting::Cmd_SetReviveEntity(StatusEntity)");
Throttle("System.Void PlayerCasting::Cmd_CastInit()");
Throttle("System.Void PlayerCasting::Rpc_QuerySkillStructs(SkillStruct[])");
Throttle("System.Void PlayerCasting::Rpc_InitSkill(System.String)");
Throttle("System.Void PlayerCasting::Rpc_SpawnEarlySkillObj()");
Throttle("System.Void PlayerCasting::Rpc_InterruptCast()");
Throttle("System.Void PlayerCasting::Rpc_CastSkill(System.String)");
Throttle("System.Void PlayerCasting::Target_InitSkillLibrary()");
Throttle("System.Void PlayerCombat::Cmd_ResetHitboxes()");
Throttle("System.Void PlayerCombat::Cmd_QuickSwapWeapon()");
Throttle("System.Void PlayerCombat::Cmd_LockWeapon()");
Throttle("System.Void PlayerCombat::Cmd_SheatheWeapon(WeaponSheatheCondition)");
Throttle("System.Void PlayerCombat::Cmd_InterruptCombat(System.Boolean)");
Throttle("System.Void PlayerCombat::Cmd_ApplyBlockCondition(System.Boolean)");
Throttle("System.Void PlayerCombat::Cmd_WeaponChargeDisplay(System.Boolean)");
Throttle("System.Void PlayerCombat::Rpc_InterruptCombat(System.Boolean)");
Throttle("System.Void PlayerCombat::Rpc_WeaponChargeDisplay(System.Boolean)");
Throttle("System.Void PlayerCombat::Target_CancelBlock()");
Throttle("System.Void PlayerEquipment::Cmd_SyncEquipStruct(EquipSyncStruct,EquipSfx)");
Throttle("System.Void PlayerEquipment::Cmd_SyncVanityStruct(EquipSyncStruct)");
Throttle("System.Void PlayerEquipment::Cmd_RemoveVanity(System.String)");
Throttle("System.Void PlayerEquipment::Rpc_EquipSfx(EquipSfx)");
Throttle("System.Void PlayerInteract::Cmd_SetPushblockParent(PushBlock)");
Throttle("System.Void PlayerInteract::Cmd_SetInteraction(Mirror.NetworkIdentity)");
Throttle("System.Void PlayerInteract::Cmd_RemoveInteraction(Mirror.NetworkIdentity)");
Throttle("System.Void PlayerInteract::Cmd_InteractWithTrigger(Mirror.NetworkIdentity)");
Throttle("System.Void PlayerInteract::Cmd_InteractWithPortal(Portal,ZoneDifficulty)");
Throttle("System.Void PlayerInteract::Cmd_OpenChest(ItemDropEntity_Chest)");
Throttle("System.Void PlayerInteract::Cmd_InteractNetItemObject(Net_ItemObject,Mirror.NetworkIdentity)");
Throttle("System.Void PlayerInteract::Rpc_OpenChest(ItemDropEntity_Chest)");
Throttle("System.Void PlayerInventory::Cmd_AddCurrency(System.Int32)");
Throttle("System.Void PlayerInventory::Cmd_SubtractCurrency(System.Int32)");
Throttle("System.Void PlayerInventory::Cmd_DropCurrency(System.Int32)");
Throttle("System.Void PlayerInventory::Cmd_PurchaseBuybackItem(NetNPC,System.Int32,System.String)");
Throttle("System.Void PlayerInventory::Cmd_SellItem(Mirror.NetworkIdentity,ItemData,System.Int32)");
Throttle("System.Void PlayerInventory::Cmd_InitBuyEffect()", 4);
Throttle("System.Void PlayerInventory::Cmd_DropItem(ItemData,System.Int32)", 4);
Throttle("System.Void PlayerInventory::Cmd_UseConsumable(ItemData)");
Throttle("System.Void PlayerInventory::Rpc_PlayBuyEffect()");
Throttle("System.Void PlayerInventory::Rpc_PlaySellEffect()");
Throttle("System.Void PlayerInventory::Rpc_Init_ConsumableObject(Player,System.String)");
Throttle("System.Void PlayerInventory::Target_RemoveItem(ItemData,System.Int32)");
Throttle("System.Void PlayerInventory::Target_AddItem(ItemData)");
Throttle("System.Void PlayerMove::Target_SetRotation(UnityEngine.Quaternion)");
Throttle("System.Void PlayerMove::Target_LockMovement(MovementLockType,System.Single)");
Throttle("System.Void PlayerMove::Target_LockLookRotationMidair()");
Throttle("System.Void PlayerMove::Target_InitJump(System.Single,System.Single,System.Single,UnityEngine.Vector3,System.Single)");
Throttle("System.Void PlayerPvp::Cmd_FlagPvp(System.Boolean)");
Throttle("System.Void PlayerQuesting::Cmd_QueryServerQuestData(System.String[],System.String[])");
Throttle("System.Void PlayerQuesting::Cmd_InitServersideQuestRewards(System.String)");
Throttle("System.Void PlayerQuesting::Target_Query_CreepKillProgress(System.String)");
Throttle("System.Void PlayerQuesting::Target_QueryQuestTriggerProgress(System.String)");
Throttle("System.Void PlayerStats::Cmd_ApplyAttributePoints(System.Int32[],System.Int32[])");
Throttle("System.Void PlayerStats::Cmd_GainProfessionExp(ResourceEntity,System.Int32)");
Throttle("System.Void PlayerStats::Cmd_RequestClass(System.String)");
Throttle("System.Void PlayerStats::Cmd_RequestClassTier(System.Int32)");
Throttle("System.Void PlayerStats::Rpc_LevelUpEffect()");
Throttle("System.Void PlayerStats::Rpc_ProfessionLevelUpEffect()");
Throttle("System.Void PlayerStats::Target_ResetSkillPoints()");
Throttle("System.Void PlayerStats::Target_DisplayExpFloatText(System.Int32)");
Throttle("System.Void PlayerTargeting::Cmd_TargetSyncCreep(Mirror.NetworkIdentity)");
Throttle("System.Void PlayerVisual::Cmd_SendNew_PlayerAppearanceStruct(PlayerAppearanceStruct)");
Throttle("System.Void PlayerVisual::Cmd_PlayTeleportEffect()", 4);
Throttle("System.Void PlayerVisual::Cmd_VanitySparkleEffect()", 4);
Throttle("System.Void PlayerVisual::Cmd_PoofSmokeEffect()", 4);
Throttle("System.Void PlayerVisual::Cmd_JumpAttackEffect()", 8);
Throttle("System.Void PlayerVisual::Cmd_CrossFadeAnim(System.String,System.Single,System.Int32)");
Throttle("System.Void PlayerVisual::Cmd_ShowItemEmote(System.String)");
Throttle("System.Void PlayerVisual::Cmd_ChangeClimbAnimationSpeed(System.Single)");
Throttle("System.Void PlayerVisual::Cmd_AltMovementAnimBool(System.Boolean)");
Throttle("System.Void PlayerVisual::Cmd_ToggleArmorRender(System.Int32,EquipCellTab)");
Throttle("System.Void PlayerVisual::Cmd_HideWeapon(System.Single)");
Throttle("System.Void PlayerVisual::Cmd_ResetSpinPlayerModel()");
Throttle("System.Void PlayerVisual::Rpc_PlayTeleportEffect()", 4);
Throttle("System.Void PlayerVisual::Rpc_VanitySparkleEffect()", 4);
Throttle("System.Void PlayerVisual::Rpc_PoofSmokeEffect()", 4);
Throttle("System.Void PlayerVisual::Rpc_JumpAttackEffect()", 8);
Throttle("System.Void PlayerVisual::Rpc_CrossFadeAnim(System.String,System.Single,System.Int32)");
Throttle("System.Void PlayerVisual::IncludeRpc_Crossfade(System.String,System.Single,System.Int32)");
Throttle("System.Void PlayerVisual::Rpc_ShowItemEmote(System.String)");
Throttle("System.Void PlayerVisual::Rpc_SetPlaybackSpeed(System.Single)");
Throttle("System.Void PlayerVisual::Rpc_AltMovementBool(System.Boolean)");
Throttle("System.Void PlayerVisual::Rpc_HideWeapon(System.Single)");
Throttle("System.Void PlayerVisual::Rpc_RandomSpinPlayerModel(System.Single)");
Throttle("System.Void PlayerVisual::Rpc_ResetSpinPlayerModel()");
Throttle("System.Void PlayerVisual::Rpc_PreventRotationLerp(System.Single)");
Throttle("System.Void PushBlock::Cmd_RemoveParentPlayer()");
Throttle("System.Void PushBlock::Request_PushBlockAction(UnityEngine.Vector3,System.Int32,System.Boolean)");
Throttle("System.Void QuestTrigger::Rpc_InitEffect()");
Throttle("System.Void StatusEntity::Cmd_AddCondition(System.Int32,System.Int32,System.Int32)");
Throttle("System.Void StatusEntity::Cmd_ReplenishAll()");
Throttle("System.Void StatusEntity::Cmd_RevivePlayer(StatusEntity)");
Throttle("System.Void StatusEntity::Cmd_SubtractMana(System.Int32)");
Throttle("System.Void StatusEntity::Cmd_SubtractStamina(System.Int32)");
Throttle("System.Void StatusEntity::Cmd_TakeDamage(System.Int32,System.Single,System.Boolean,System.Boolean,DamageWeight,UnityEngine.Vector3,UnityEngine.Vector3)");
Throttle("System.Void StatusEntity::Rpc_AngelaTearEffect()");
Throttle("System.Void StatusEntity::Rpc_DisplayHitEffect(DamageWeight,System.Int32,UnityEngine.Vector3)");
Throttle("System.Void StatusEntity::Rpc_DisplayBlockHitEffect(StatusEntity,System.Int32,System.Boolean,System.Boolean,UnityEngine.Vector3)");
Throttle("System.Void StatusEntity::Rpc_DisplayAbsorbHitEffect()");
Throttle("System.Void StatusEntity::Rpc_DisplayCritHitEffect(StatusEntity,UnityEngine.Vector3)");
Throttle("System.Void StatusEntity::Rpc_DisplayMissHitEffect(StatusEntity)");
Throttle("System.Void StatusEntityGUI::Target_Display_FloatingNumber(StatusEntity,FloatTextColor,System.Int32,System.Int32,System.Int32)");
}
private static void Throttle(string functionName)
{
Throttle(functionName, 400);
}
private static void Throttle(string functionName, int rateLimit)
{
ushort num = Hash(functionName);
Match match = NameRegex.Match(functionName);
CustomRateLimits.Add(num, new ThrottleData
{
Limit = rateLimit,
MethodName = (match.Success ? match.Groups[1].Value : functionName),
FunctionHash = num
});
}
private static ushort Hash(string functionName)
{
return (ushort)((uint)Extensions.GetStableHashCode(functionName) & 0xFFFFu);
}
private static AbuseDetectorTokenBucket CreateDetector(ushort functionHash)
{
if (!CustomRateLimits.TryGetValue(functionHash, out var value))
{
value = (CustomRateLimits[functionHash] = new ThrottleData
{
FunctionHash = functionHash,
Limit = 40,
MethodName = ""
});
Logging.LogDebug("Got an unconfigured CMD/RPC function (" + GetMethodName(functionHash) + ")! Will throttle using default limit for unspecified methods.", PerfectGuard.DetailedLogging);
}
return new AbuseDetectorTokenBucket(value.Limit);
}
private static bool CheckRateLimits(uint netId, ushort functionHash, byte componentIndex, bool isRpc)
{
if (!PerfectGuard.NetworkRateLimitingEnabled)
{
return true;
}
NetworkIdentity value;
if (isRpc)
{
if (!NetworkClient.active || !NetworkClient.spawned.TryGetValue(netId, out value))
{
return true;
}
}
else if (!NetworkServer.active || !NetworkServer.spawned.TryGetValue(netId, out value))
{
return true;
}
if (0 > componentIndex || componentIndex >= value.NetworkBehaviours.Length)
{
return true;
}
NetworkBehaviour val = value.NetworkBehaviours[componentIndex];
AbuseDetectorTokenBucket orAdd = Detectors.GetOrAdd(functionHash, CreateDetector);
AbuseDetectorTokenBucket.RateLimitData rateLimitData = orAdd.TrackEvent(val);
if (rateLimitData.IsRateLimited && DateTime.Now - rateLimitData.PreviousRateLimitAt >= TimeSpan.FromSeconds(5.0))
{
Logging.LogWarning($"Network spam detected! ({((Object)val).name}, {GetMethodName(functionHash)}, {orAdd.RateLimit}/s, {orAdd.BurstLimit} burst)", PerfectGuard.DetailedLogging);
}
return !rateLimitData.IsRateLimited;
}
private static string GetMethodName(ushort functionHash)
{
if (CustomRateLimits.TryGetValue(functionHash, out var value))
{
return value.MethodName;
}
if (RemoteProcedureCalls.remoteCallDelegates.TryGetValue(functionHash, out var value2))
{
string name = ((Delegate)(object)value2.function).Method.Name;
Match match = NameRegex.Match(((Delegate)(object)value2.function).Method.Name);
return match.Success ? match.Groups[1].Value : name;
}
return $"<hash {functionHash}>";
}
[HarmonyPatch(typeof(NetworkClient), "OnRPCMessage")]
[HarmonyPrefix]
private static bool RpcThrottle(ref RpcMessage message)
{
return CheckRateLimits(message.netId, message.functionHash, message.componentIndex, isRpc: true);
}
[HarmonyPatch(typeof(NetworkServer), "OnCommandMessage")]
[HarmonyPrefix]
private static bool CmdThrottle(ref CommandMessage msg)
{
return CheckRateLimits(msg.netId, msg.functionHash, msg.componentIndex, isRpc: false);
}
}
[HarmonyPatch]
public class NetItemObjectTrackerInjector
{
[HarmonyPatch(typeof(Net_ItemObject), "Awake")]
[HarmonyPostfix]
private static void InjectTracker(Net_ItemObject __instance)
{
if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<NetItemObjectTracker>()))
{
((Component)__instance).gameObject.AddComponent<NetItemObjectTracker>();
}
}
}
[HarmonyPatch]
internal static class PreventAudioSpam
{
private const float AudioSpamCooldownSeconds = 0.1f;
private static readonly Dictionary<AudioSource, float> AudioCooldowns = new Dictionary<AudioSource, float>();
private static readonly List<AudioSource> DeadAudioSources = new List<AudioSource>();
[HarmonyPrefix]
[HarmonyPatch(typeof(AudioSource), "Play", new Type[] { })]
public static bool AudioSource_Play_Prefix(AudioSource __instance)
{
return CheckAudioCooldown(__instance);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(AudioSource), "PlayOneShot", new Type[]
{
typeof(AudioClip),
typeof(float)
})]
public static bool AudioSource_PlayOneShot_Prefix(AudioSource __instance)
{
return CheckAudioCooldown(__instance);
}
internal static bool CheckAudioCooldown(AudioSource instance)
{
if (!PerfectGuard.AudioRateLimitingEnabled)
{
return true;
}
if ((Object)(object)instance == (Object)null || !((Component)instance).gameObject.activeInHierarchy)
{
return false;
}
if (AudioCooldowns.TryGetValue(instance, out var value) && Time.time < value)
{
return false;
}
AudioCooldowns[instance] = Time.time + 0.1f;
return true;
}
internal static void CleanupDeadAudioSources()
{
DeadAudioSources.Clear();
DeadAudioSources.AddRange(AudioCooldowns.Keys.Where((AudioSource audioSource) => (Object)(object)audioSource == (Object)null));
foreach (AudioSource deadAudioSource in DeadAudioSources)
{
AudioCooldowns.Remove(deadAudioSource);
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}