using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MycopunkShared;
using Pigeon.Movement;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.2")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[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;
}
}
}
internal static class AttackerResolver
{
public static Player Resolve(IDamageSource source)
{
IDamageSource obj = source.GetBase();
Player val = (Player)(object)((obj is Player) ? obj : null);
if ((Object)(object)val != (Object)null)
{
return val;
}
Gun val2 = (Gun)(object)((source is Gun) ? source : null);
if ((Object)(object)val2 != (Object)null && (Object)(object)val2.Player != (Object)null)
{
return val2.Player;
}
Throwable val3 = (Throwable)(object)((source is Throwable) ? source : null);
if ((Object)(object)val3 != (Object)null && (Object)(object)val3.Player != (Object)null)
{
return val3.Player;
}
NetworkBehaviour val4 = (NetworkBehaviour)(object)((source is IGear) ? ((source is NetworkBehaviour) ? source : null) : null);
if ((Object)(object)val4 == (Object)null || !val4.IsSpawned || GameManager.players == null)
{
return null;
}
foreach (Player player in GameManager.players)
{
if ((Object)(object)player != (Object)null && ((NetworkBehaviour)player).OwnerClientId == val4.OwnerClientId)
{
return player;
}
}
return null;
}
}
internal sealed class BurstLabel
{
private TextMeshProUGUI label;
private Canvas canvas;
private string shown;
public void Refresh(TextMeshProUGUI template, double damage, float remaining)
{
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
if (damage <= 0.0 || (Object)(object)template == (Object)null || (Object)(object)((Graphic)template).canvas == (Object)null || !((Behaviour)((Graphic)template).canvas.rootCanvas).isActiveAndEnabled || HudVisibility.ResultsOpen())
{
if ((Object)(object)label != (Object)null)
{
((Component)label).gameObject.SetActive(false);
}
return;
}
Canvas rootCanvas = ((Graphic)template).canvas.rootCanvas;
if ((Object)(object)label == (Object)null || (Object)(object)canvas != (Object)(object)rootCanvas)
{
Clear();
canvas = rootCanvas;
label = GameHudText.Create(template, ((Component)rootCanvas).transform, "DPS Checker Burst Damage");
((TMP_Text)label).alignment = (TextAlignmentOptions)4097;
((TMP_Text)label).fontSize = 20f;
((TMP_Text)label).fontStyle = (FontStyles)1;
RectTransform rectTransform = ((TMP_Text)label).rectTransform;
Vector2 val = default(Vector2);
((Vector2)(ref val))..ctor(0.5f, 0.5f);
rectTransform.anchorMax = val;
rectTransform.anchorMin = val;
rectTransform.pivot = Vector2.zero;
rectTransform.anchoredPosition = new Vector2(32f, -28f);
rectTransform.sizeDelta = new Vector2(220f, 28f);
((Transform)rectTransform).localScale = Vector3.one;
((Transform)rectTransform).localRotation = Quaternion.identity;
((TMP_Text)label).transform.SetAsLastSibling();
}
string text = Math.Ceiling(damage).ToString("0", CultureInfo.InvariantCulture);
if (shown != text)
{
shown = text;
((TMP_Text)label).text = text;
}
Color white = Color.white;
white.a = Mathf.Clamp01(remaining / 0.8f);
((Graphic)label).color = white;
if (!((Component)label).gameObject.activeSelf)
{
((Component)label).gameObject.SetActive(true);
}
}
public void Clear()
{
if ((Object)(object)label != (Object)null)
{
Object.Destroy((Object)(object)((Component)label).gameObject);
}
label = null;
canvas = null;
shown = null;
}
}
internal struct CombatStats
{
public float Dps;
public float Max;
public float TotalDamage;
public int Kills;
public bool TotalsKnown;
public bool DamageKnown;
public static string Compact(float value)
{
if (value < 1000f)
{
return value.ToString("0", CultureInfo.InvariantCulture);
}
if (value < 999950f)
{
return (value / 1000f).ToString("0.#", CultureInfo.InvariantCulture) + "k";
}
return (value / 1000000f).ToString("0.#", CultureInfo.InvariantCulture) + "m";
}
public string Format(bool dpsEstimated, bool totalsEstimated, bool local = false)
{
string text = (dpsEstimated ? "~" : "");
string text2 = (totalsEstimated ? "~" : "");
string text3 = ((totalsEstimated && (dpsEstimated || !TotalsKnown)) ? "~" : "");
return "DPS " + text + Compact(Dps) + " T " + text2 + Compact(TotalDamage) + " K " + text3 + Kills;
}
}
internal sealed class StatsText
{
private string text;
private float dps;
private float totalDamage;
private int kills;
private int flags = -1;
public string Get(CombatStats stats, bool dpsEstimated, bool totalsEstimated, bool local = false)
{
int num = (int)((dpsEstimated ? 1u : 0u) | (uint)(totalsEstimated ? 2 : 0)) | (local ? 4 : 0);
if (text == null || !stats.Dps.Equals(dps) || !stats.TotalDamage.Equals(totalDamage) || stats.Kills != kills || num != flags)
{
text = stats.Format(dpsEstimated, totalsEstimated, local);
dps = stats.Dps;
totalDamage = stats.TotalDamage;
kills = stats.Kills;
flags = num;
}
return text;
}
}
internal sealed class DamageRpcHooks : IDisposable
{
private sealed class Hook
{
public RpcReceiveHandler Original;
public RpcReceiveHandler Wrapper;
public uint RpcId;
}
private const uint EnemyDamageRpcId = 3500258196u;
private const uint TrainingDamageRpcId = 4264469793u;
private const uint EnemyKillRpcId = 3954280513u;
private readonly Dictionary<Type, Dictionary<uint, RpcReceiveHandler>> table;
private readonly Dictionary<Type, Dictionary<uint, Hook>> hooks = new Dictionary<Type, Dictionary<uint, Hook>>();
private readonly Action<NetworkBehaviour, FastBufferReader> observeDamage;
private readonly Action<NetworkBehaviour, FastBufferReader> observeKill;
private readonly ManualLogSource log;
private bool installedLogged;
private bool skippedLogged;
private bool errorLogged;
public DamageRpcHooks(ManualLogSource log, Action<NetworkBehaviour, FastBufferReader> observeDamage, Action<NetworkBehaviour, FastBufferReader> observeKill)
{
this.log = log;
this.observeDamage = observeDamage;
this.observeKill = observeKill;
FieldInfo field = typeof(NetworkBehaviour).GetField("__rpc_func_table", BindingFlags.Static | BindingFlags.NonPublic);
if (field == null)
{
throw new MissingFieldException("NetworkBehaviour.__rpc_func_table");
}
table = field.GetValue(null) as Dictionary<Type, Dictionary<uint, RpcReceiveHandler>>;
if (table == null)
{
throw new InvalidOperationException("Unsupported RPC table type.");
}
}
public void InstallExisting()
{
foreach (Type key in table.Keys)
{
Install(key);
}
}
public void Install(Type type)
{
try
{
bool flag = typeof(EnemyPart).IsAssignableFrom(type);
bool flag2 = typeof(DynamicTrainingTarget).IsAssignableFrom(type);
if (!flag && !flag2)
{
return;
}
uint rpcId = (flag ? 3500258196u : 4264469793u);
Type declaringType = (flag ? typeof(EnemyPart) : typeof(ObjectTarget));
if (table.TryGetValue(type, out var value))
{
InstallHandler(type, value, rpcId, declaringType, observeDamage);
if (typeof(EnemyCore).IsAssignableFrom(type))
{
InstallHandler(type, value, 3954280513u, typeof(EnemyPart), observeKill);
}
}
}
catch (Exception ex)
{
if (!errorLogged)
{
log.LogWarning((object)("DPS estimate: could not observe an enemy RPC: " + ex));
}
errorLogged = true;
}
}
private void InstallHandler(Type type, Dictionary<uint, RpcReceiveHandler> handlers, uint rpcId, Type declaringType, Action<NetworkBehaviour, FastBufferReader> observe)
{
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
if (!hooks.TryGetValue(type, out var value))
{
value = (hooks[type] = new Dictionary<uint, Hook>());
}
if (value.ContainsKey(rpcId) || !handlers.TryGetValue(rpcId, out var original))
{
return;
}
if (original == null || ((Delegate)(object)original).Method.DeclaringType != declaringType || ((Delegate)(object)original).Method.Name != "__rpc_handler_" + rpcId)
{
if (!skippedLogged)
{
log.LogWarning((object)"DPS estimate: unsupported or modified target RPC handler; estimation skipped for that handler.");
}
skippedLogged = true;
return;
}
RpcReceiveHandler val = (RpcReceiveHandler)delegate(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
try
{
observe(target, reader);
}
catch (Exception ex)
{
if (!errorLogged)
{
log.LogWarning((object)("DPS estimate: RPC observation failed: " + ex));
}
errorLogged = true;
}
original.Invoke(target, reader, rpcParams);
};
value.Add(rpcId, new Hook
{
Original = original,
Wrapper = val,
RpcId = rpcId
});
handlers[rpcId] = val;
if (!installedLogged)
{
log.LogInfo((object)"DPS estimate: registered target RPC observer.");
}
installedLogged = true;
}
public void Dispose()
{
foreach (KeyValuePair<Type, Dictionary<uint, Hook>> hook in hooks)
{
if (!table.TryGetValue(hook.Key, out var value))
{
continue;
}
foreach (Hook value3 in hook.Value.Values)
{
if (value.TryGetValue(value3.RpcId, out var value2) && (Delegate?)(object)value2 == (Delegate?)(object)value3.Wrapper)
{
value[value3.RpcId] = value3.Original;
}
}
}
hooks.Clear();
}
}
internal static class DamageRpcReader
{
public unsafe static void Read(FastBufferReader original, out DamageData damage, out NetworkBehaviourReference source)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
FastBufferReader val = default(FastBufferReader);
((FastBufferReader)(ref val))..ctor(original, (Allocator)1, ((FastBufferReader)(ref original)).Length, ((FastBufferReader)(ref original)).Position, (Allocator)2);
try
{
((FastBufferReader)(ref val)).ReadValueSafe<DamageData>(ref damage, default(ForStructs));
((FastBufferReader)(ref val)).ReadValueSafe<NetworkBehaviourReference>(ref source, default(ForNetworkSerializable));
}
finally
{
((IDisposable)(*(FastBufferReader*)(&val))/*cast due to .constrained prefix*/).Dispose();
}
}
public unsafe static NetworkBehaviourReference ReadKillSource(FastBufferReader original)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
FastBufferReader val = default(FastBufferReader);
((FastBufferReader)(ref val))..ctor(original, (Allocator)1, ((FastBufferReader)(ref original)).Length, ((FastBufferReader)(ref original)).Position, (Allocator)2);
try
{
NetworkBehaviourReference result = default(NetworkBehaviourReference);
((FastBufferReader)(ref val)).ReadValueSafe<NetworkBehaviourReference>(ref result, default(ForNetworkSerializable));
return result;
}
finally
{
((IDisposable)(*(FastBufferReader*)(&val))/*cast due to .constrained prefix*/).Dispose();
}
}
}
internal sealed class DpsNetwork : IDisposable
{
private const string Message = "mycopunk.dpschecker.v1";
private readonly ManualLogSource log;
private readonly RemoteDps values = new RemoteDps();
private readonly HashSet<ulong> peers = new HashSet<ulong>();
private NetworkManager manager;
private float nextSend;
private bool failed;
private bool registered;
public DpsNetwork(ManualLogSource log)
{
this.log = log;
}
public bool TryGet(ulong id, out CombatStats value)
{
return values.TryGet(id, Time.unscaledTime, out value);
}
public void ClearValues()
{
values.Clear();
nextSend = 0f;
}
public void Tick(CombatStats localStats)
{
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
NetworkManager singleton = NetworkManager.Singleton;
if ((Object)(object)singleton != (Object)(object)manager || ((Object)(object)manager != (Object)null && !manager.IsListening))
{
Dispose();
manager = (((Object)(object)singleton != (Object)null && singleton.IsListening) ? singleton : null);
failed = false;
}
if ((Object)(object)manager == (Object)null || failed || !manager.IsListening || (!manager.IsServer && !manager.IsConnectedClient))
{
return;
}
try
{
if (manager.CustomMessagingManager == null)
{
return;
}
if (!registered)
{
manager.CustomMessagingManager.RegisterNamedMessageHandler("mycopunk.dpschecker.v1", new HandleNamedMessageDelegate(OnMessage));
manager.OnClientDisconnectCallback += OnDisconnect;
registered = true;
}
if (Time.unscaledTime < nextSend)
{
return;
}
if (!manager.IsServer)
{
nextSend = Time.unscaledTime + (values.TryGet(0uL, Time.unscaledTime, out var _) ? 0.25f : 1f);
Send(0uL, manager.LocalClientId, localStats);
return;
}
nextSend = Time.unscaledTime + 0.25f;
foreach (ulong peer in peers)
{
Send(peer, manager.LocalClientId, localStats);
foreach (ulong peer2 in peers)
{
if (peer2 != peer && values.TryGet(peer2, Time.unscaledTime, out var value2))
{
Send(peer, peer2, value2);
}
}
}
}
catch (Exception ex)
{
log.LogWarning((object)("DPS sharing disabled for this session: " + ex));
failed = true;
}
}
private unsafe void Send(ulong recipient, ulong source, CombatStats value)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
FastBufferWriter val = default(FastBufferWriter);
((FastBufferWriter)(ref val))..ctor(26, (Allocator)2, -1);
try
{
((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref source, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref value.Dps, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref value.Max, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref value.Kills, default(ForPrimitives));
byte b = (value.TotalsKnown ? ((byte)1) : ((byte)0));
((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref value.TotalDamage, default(ForPrimitives));
b = (value.DamageKnown ? ((byte)1) : ((byte)0));
((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives));
manager.CustomMessagingManager.SendNamedMessage("mycopunk.dpschecker.v1", recipient, val, (NetworkDelivery)1);
}
finally
{
((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose();
}
}
private void OnMessage(ulong sender, FastBufferReader reader)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
try
{
CombatStats value = default(CombatStats);
ulong num = default(ulong);
((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives));
((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref value.Dps, default(ForPrimitives));
if (((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 9)
{
((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref value.Max, default(ForPrimitives));
((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref value.Kills, default(ForPrimitives));
byte b = default(byte);
((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives));
if (b > 1)
{
return;
}
value.TotalsKnown = b == 1;
}
if (((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position >= 5)
{
((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref value.TotalDamage, default(ForPrimitives));
byte b2 = default(byte);
((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b2, default(ForPrimitives));
if (b2 > 1)
{
return;
}
value.DamageKnown = b2 == 1;
}
if (manager.IsServer)
{
num = sender;
if (sender != manager.LocalClientId && manager.ConnectedClients.ContainsKey(sender) && values.Set(num, value, Time.unscaledTime))
{
peers.Add(sender);
}
}
else if (sender == 0L && num != manager.LocalClientId)
{
values.Set(num, value, Time.unscaledTime);
}
}
catch (Exception ex)
{
log.LogWarning((object)("Invalid DPS message: " + ex.Message));
}
}
private void OnDisconnect(ulong id)
{
peers.Remove(id);
values.Remove(id);
}
public void Dispose()
{
if ((Object)(object)manager != (Object)null && registered)
{
manager.OnClientDisconnectCallback -= OnDisconnect;
if (manager.CustomMessagingManager != null)
{
manager.CustomMessagingManager.UnregisterNamedMessageHandler("mycopunk.dpschecker.v1");
}
}
registered = false;
peers.Clear();
values.Clear();
manager = null;
nextSend = 0f;
}
}
internal sealed class DpsWindow
{
private readonly Queue<KeyValuePair<float, float>> hits = new Queue<KeyValuePair<float, float>>();
private float total;
private double burstDamage;
private float lastBurstTime;
private bool burstActive;
public float Peak { get; private set; }
public float TotalDamage { get; private set; }
public int Kills { get; private set; }
public void Add(float time, float damage)
{
if (!(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage))
{
Current(time);
hits.Enqueue(new KeyValuePair<float, float>(time, damage));
total += damage;
TotalDamage += damage;
if (total > Peak)
{
Peak = total;
}
}
}
public void AddKill()
{
Kills++;
}
public void AddBurst(float time, float damage)
{
if (!(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage))
{
if (!burstActive || time - lastBurstTime >= 4.5f)
{
burstDamage = 0.0;
}
burstDamage += damage;
lastBurstTime = time;
burstActive = true;
}
}
public CombatStats Snapshot(float time)
{
return new CombatStats
{
Dps = Current(time),
Max = Peak,
TotalDamage = TotalDamage,
Kills = Kills,
TotalsKnown = true,
DamageKnown = true
};
}
public double Burst(float time, out float remaining)
{
remaining = (burstActive ? (4.5f - (time - lastBurstTime)) : 0f);
if (remaining <= 0f)
{
burstDamage = 0.0;
burstActive = false;
return 0.0;
}
return burstDamage;
}
public float Current(float time)
{
while (hits.Count > 0 && time - hits.Peek().Key >= 1f)
{
total -= hits.Dequeue().Value;
}
if (hits.Count == 0)
{
total = 0f;
}
return total;
}
public void Clear()
{
hits.Clear();
total = 0f;
Peak = 0f;
TotalDamage = 0f;
Kills = 0;
burstDamage = 0.0;
lastBurstTime = 0f;
burstActive = false;
}
}
internal sealed class EstimatedDps
{
private sealed class PlayerDamage
{
public readonly DpsWindow Window = new DpsWindow();
}
private readonly Dictionary<ulong, PlayerDamage> players = new Dictionary<ulong, PlayerDamage>();
public void Add(ulong id, float time, float damage)
{
if (!(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage))
{
if (!players.TryGetValue(id, out var value))
{
value = (players[id] = new PlayerDamage());
}
value.Window.Add(time, damage);
}
}
public void AddKill(ulong id)
{
if (!players.TryGetValue(id, out var value))
{
value = (players[id] = new PlayerDamage());
}
value.Window.AddKill();
}
public bool TryGet(ulong id, float time, out CombatStats stats)
{
if (players.TryGetValue(id, out var value))
{
stats = value.Window.Snapshot(time);
return true;
}
stats = default(CombatStats);
return false;
}
public void Clear()
{
players.Clear();
}
}
internal sealed class LocalDpsLabel
{
private TextMeshProUGUI template;
private TextMeshProUGUI label;
private readonly Vector3[] corners = (Vector3[])(object)new Vector3[4];
private readonly StatsText text = new StatsText();
public bool Visible
{
get
{
if ((Object)(object)label != (Object)null)
{
return ((Component)label).gameObject.activeInHierarchy;
}
return false;
}
}
public void Refresh(TextMeshProUGUI title, EquippableHUDOverlay[] overlays, CombatStats stats)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
//IL_0202: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_0277: Unknown result type (might be due to invalid IL or missing references)
//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
//IL_02de: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = null;
Vector3 val2 = Vector3.zero;
bool flag = false;
if ((Object)(object)title != (Object)null && overlays != null)
{
foreach (EquippableHUDOverlay val3 in overlays)
{
if ((Object)(object)val3 == (Object)null || !((Component)val3).gameObject.activeInHierarchy)
{
continue;
}
Transform transform = ((Component)val3).transform;
RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if (!((Object)(object)val4 == (Object)null) && ((Transform)val4).parent is RectTransform)
{
if ((Object)(object)val == (Object)null)
{
val = (RectTransform)((Transform)val4).parent;
}
val4.GetWorldCorners(corners);
Vector3 val5 = ((Transform)val).InverseTransformPoint(corners[1]);
if (!flag || val5.y > val2.y)
{
val2 = val5;
}
flag = true;
}
}
}
if ((Object)(object)val == (Object)null)
{
Clear();
return;
}
if ((Object)(object)template != (Object)(object)title || (Object)(object)label == (Object)null || (Object)(object)((TMP_Text)label).transform.parent != (Object)(object)val)
{
Clear();
template = title;
label = Object.Instantiate<TextMeshProUGUI>(title, (Transform)(object)val, false);
((Object)label).name = "DPS Checker Local";
((Graphic)label).raycastTarget = false;
((TMP_Text)label).richText = false;
((TMP_Text)label).textWrappingMode = (TextWrappingModes)0;
((TMP_Text)label).overflowMode = (TextOverflowModes)0;
((TMP_Text)label).alignment = (TextAlignmentOptions)1025;
((TMP_Text)label).enableAutoSizing = false;
((TMP_Text)label).fontSize = Mathf.Max(((TMP_Text)title).fontSize * 1.2f, 20f);
Outline val6 = ((Component)label).GetComponent<Outline>();
if ((Object)(object)val6 == (Object)null)
{
val6 = ((Component)label).gameObject.AddComponent<Outline>();
}
((Shadow)val6).effectColor = new Color(0f, 0f, 0f, 0.9f);
((Shadow)val6).effectDistance = new Vector2(1f, -1f);
RectTransform rectTransform = ((TMP_Text)label).rectTransform;
RectTransform rectTransform2 = ((TMP_Text)label).rectTransform;
Vector2 val7 = default(Vector2);
((Vector2)(ref val7))..ctor(0.5f, 0.5f);
rectTransform2.anchorMax = val7;
rectTransform.anchorMin = val7;
((TMP_Text)label).rectTransform.pivot = Vector2.zero;
((TMP_Text)label).rectTransform.sizeDelta = new Vector2(420f, ((TMP_Text)label).fontSize * 1.5f);
((Component)label).gameObject.SetActive(true);
}
string text = this.text.Get(stats, dpsEstimated: false, totalsEstimated: false, local: true);
GameHudText.SetText(label, text);
((Graphic)label).color = Color.white;
((Transform)((TMP_Text)label).rectTransform).localPosition = val2 + new Vector3(0f, 4f, 0f);
}
public void Clear()
{
if ((Object)(object)label != (Object)null)
{
Object.Destroy((Object)(object)((Component)label).gameObject);
}
label = null;
template = null;
}
}
[BepInPlugin("f1w3.mycopunk.dpschecker", "DPS Checker", "0.2.2")]
[BepInDependency("doku_macaron.mycopunk.macaroncore", "1.1.0")]
[BepInProcess("Mycopunk.exe")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(PlayerData), "OnLocalPlayerDamageTarget")]
private static class LocalDamagePatch
{
[HarmonyPostfix]
private static void Postfix(ref DamageCallbackData data)
{
OnDamage(ref data);
}
}
[HarmonyPatch(typeof(PlayerData), "OnLocalPlayerKillTarget")]
private static class LocalKillPatch
{
[HarmonyPostfix]
private static void Postfix(ref KillCallbackData data)
{
OnLocalKill(ref data);
}
}
[HarmonyPatch(typeof(TeammateHUD), "Initialize")]
private static class TeammateInitializePatch
{
[HarmonyPostfix]
private static void Postfix(TeammateHUD __instance, Player player)
{
OnTeammateInitialize(__instance, player);
}
}
[HarmonyPatch(typeof(Highlighter), "OnDamageTarget")]
private static class BurstDamagePatch
{
[HarmonyPrefix]
private static void Prefix(ref DamageCallbackData data)
{
OnBurstDamage(ref data);
}
}
[HarmonyPatch(typeof(MissionManager), "OnMissionStarted_Client")]
private static class MissionStartedPatch
{
[HarmonyPostfix]
private static void Postfix(MissionManager __instance)
{
OnMissionBoundary(__instance);
}
}
[HarmonyPatch(typeof(MissionManager), "OnDestroy")]
private static class MissionDestroyPatch
{
[HarmonyPrefix]
private static void Prefix(MissionManager __instance)
{
OnMissionBoundary(__instance);
}
}
[HarmonyPatch(typeof(EnemyPart), "ApplyDamage_Server")]
private static class EnemyDamageServerPatch
{
[HarmonyPrefix]
private static void Prefix(EnemyPart __instance, DamageData data, IDamageSource source)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
OnEnemyDamageServer(__instance, data, source);
}
}
[HarmonyPatch(typeof(ObjectTarget), "ApplyDamage_Server")]
private static class ObjectDamageServerPatch
{
[HarmonyPrefix]
private static void Prefix(ObjectTarget __instance, DamageData data, IDamageSource source)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
OnObjectDamageServer(__instance, data, source);
}
}
[HarmonyPatch(typeof(EnemyPart), "Kill_Server")]
private static class EnemyKillServerPatch
{
[HarmonyPrefix]
private static void Prefix(EnemyPart __instance, IDamageSource source)
{
OnEnemyKillServer(__instance, source);
}
}
[HarmonyPatch(typeof(NetworkBehaviour), "InitializeVariables")]
private static class NetworkVariablesPatch
{
[HarmonyPostfix]
private static void Postfix(NetworkBehaviour __instance)
{
OnNetworkVariablesInitialized(__instance);
}
}
private static readonly DpsWindow Window = new DpsWindow();
private static readonly HashSet<EnemyCore> EstimatedKills = new HashSet<EnemyCore>();
private static readonly EstimatedDps Estimates = new EstimatedDps();
private readonly LocalDpsLabel localLabel = new LocalDpsLabel();
private readonly BurstLabel burstLabel = new BurstLabel();
private readonly StatsText fallbackText = new StatsText();
private Harmony harmony;
private bool ready;
private bool localHudFailed;
private bool burstHudFailed;
private bool missionHooksReady;
private DpsNetwork network;
private DamageRpcHooks damageRpcHooks;
private static bool estimateErrorLogged;
private static bool estimateRpcLogged;
private static bool estimateEventLogged;
private static bool estimateMissingSourceLogged;
private static bool estimateUnknownSourceLogged;
private static bool estimateSuccessLogged;
private bool estimateDisplayLogged;
internal static Plugin Instance { get; private set; }
private void Awake()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
try
{
harmony = new Harmony("mycopunk.dpschecker");
harmony.CreateClassProcessor(typeof(LocalDamagePatch)).Patch();
harmony.CreateClassProcessor(typeof(LocalKillPatch)).Patch();
SceneManager.sceneLoaded += OnSceneLoaded;
network = new DpsNetwork(((BaseUnityPlugin)this).Logger);
Instance = this;
ModChannels.Publish("MycopunkShared.DpsChecker.Stats.v1", (object)new Func<ulong, string>(StatsFor));
ready = true;
Hotkeys.ReportConflicts((BaseUnityPlugin)(object)this);
((BaseUnityPlugin)this).Logger.LogInfo((object)"DPS Checker loaded.");
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("DPS Checker could not hook damage events: " + ex));
if (harmony != null)
{
harmony.UnpatchSelf();
}
return;
}
try
{
harmony.CreateClassProcessor(typeof(TeammateInitializePatch)).Patch();
TeammateHUD[] array = Object.FindObjectsByType<TeammateHUD>((FindObjectsInactive)1);
foreach (TeammateHUD val in array)
{
Player player = val.player;
if (player != null)
{
OnTeammateInitialize(val, player);
}
}
}
catch (Exception ex2)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS teammate HUD could not be hooked: " + ex2));
}
try
{
harmony.CreateClassProcessor(typeof(BurstDamagePatch)).Patch();
}
catch (Exception ex3)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS burst damage could not be hooked: " + ex3));
}
try
{
harmony.CreateClassProcessor(typeof(MissionStartedPatch)).Patch();
harmony.CreateClassProcessor(typeof(MissionDestroyPatch)).Patch();
missionHooksReady = true;
}
catch (Exception ex4)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS mission reset hooks could not be installed: " + ex4));
}
try
{
harmony.CreateClassProcessor(typeof(EnemyDamageServerPatch)).Patch();
harmony.CreateClassProcessor(typeof(ObjectDamageServerPatch)).Patch();
harmony.CreateClassProcessor(typeof(EnemyKillServerPatch)).Patch();
damageRpcHooks = new DamageRpcHooks(((BaseUnityPlugin)this).Logger, OnEnemyDamageRpc, OnEnemyKillRpc);
harmony.CreateClassProcessor(typeof(NetworkVariablesPatch)).Patch();
damageRpcHooks.InstallExisting();
((BaseUnityPlugin)this).Logger.LogInfo((object)"DPS estimate: damage hooks installed.");
}
catch (Exception ex5)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS estimation could not be hooked: " + ex5));
}
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
try
{
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS hook cleanup failed: " + ex));
}
try
{
if (damageRpcHooks != null)
{
damageRpcHooks.Dispose();
}
}
catch (Exception ex2)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS RPC cleanup failed: " + ex2));
}
try
{
if (network != null)
{
network.Dispose();
}
}
catch (Exception ex3)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS network cleanup failed: " + ex3));
}
localLabel.Clear();
burstLabel.Clear();
Instance = null;
ModChannels.Publish("MycopunkShared.DpsChecker.Stats.v1", (object)null);
TeammateDpsLabel[] array = Object.FindObjectsByType<TeammateDpsLabel>((FindObjectsInactive)1);
for (int i = 0; i < array.Length; i++)
{
Object.Destroy((Object)(object)array[i]);
}
Window.Clear();
Estimates.Clear();
EstimatedKills.Clear();
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (!missionHooksReady)
{
ResetStats();
}
localLabel.Clear();
burstLabel.Clear();
localHudFailed = false;
burstHudFailed = false;
}
private static void OnMissionBoundary(MissionManager __instance)
{
if ((Object)(object)Instance == (Object)null || (Object)(object)__instance != (Object)(object)MissionManager.Instance)
{
return;
}
try
{
Instance.ResetStats();
}
catch (Exception ex)
{
((BaseUnityPlugin)Instance).Logger.LogWarning((object)("DPS mission reset failed: " + ex));
}
}
private void ResetStats()
{
Window.Clear();
Estimates.Clear();
EstimatedKills.Clear();
if (network != null)
{
network.ClearValues();
}
}
private static void OnDamage(ref DamageCallbackData data)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
float damage = data.damageData.damage;
if (data.target != null && ((((IFollowable)data.target).Type & 1) != 0 || data.target is DynamicTrainingTarget) && !(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage))
{
Window.Add(Time.unscaledTime, damage);
}
}
private static void OnBurstDamage(ref DamageCallbackData data)
{
if ((Object)(object)Instance == (Object)null || !Instance.ready)
{
return;
}
float damage = data.damageData.damage;
if (damage <= 0f || float.IsNaN(damage) || float.IsInfinity(damage))
{
return;
}
try
{
if ((object)data.target != Player.LocalPlayer || data.source == null || (object)data.source.GetBase() != data.target)
{
Window.AddBurst(Time.unscaledTime, damage);
}
}
catch (Exception ex)
{
((BaseUnityPlugin)Instance).Logger.LogWarning((object)("DPS burst damage could not be recorded: " + ex.Message));
}
}
private void Update()
{
if (ready)
{
network.Tick(Window.Snapshot(Time.unscaledTime));
}
}
private void LateUpdate()
{
if (!ready)
{
return;
}
if (!burstHudFailed)
{
try
{
PlayerLook instance = PlayerLook.Instance;
float remaining;
double damage = Window.Burst(Time.unscaledTime, out remaining);
burstLabel.Refresh(((Object)(object)instance != (Object)null) ? instance.PlayerTitleText : null, damage, remaining);
}
catch (Exception ex)
{
burstHudFailed = true;
burstLabel.Clear();
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS burst HUD could not be created: " + ex));
}
}
if (localHudFailed)
{
return;
}
try
{
PlayerLook instance2 = PlayerLook.Instance;
Player localPlayer = Player.LocalPlayer;
EquippableHUDOverlay[] overlays = (((Object)(object)localPlayer != (Object)null) ? localPlayer.gearHUDs : null);
localLabel.Refresh(((Object)(object)instance2 != (Object)null) ? instance2.PlayerTitleText : null, overlays, Window.Snapshot(Time.unscaledTime));
}
catch (Exception ex2)
{
localHudFailed = true;
localLabel.Clear();
((BaseUnityPlugin)this).Logger.LogWarning((object)("DPS local HUD could not be created: " + ex2));
}
}
private static void OnLocalKill(ref KillCallbackData data)
{
if (data.target is EnemyCore)
{
Window.AddKill();
}
}
private static string StatsFor(ulong clientId)
{
try
{
if ((Object)(object)Instance == (Object)null)
{
return null;
}
NetworkManager singleton = NetworkManager.Singleton;
if ((Object)(object)singleton != (Object)null && clientId == singleton.LocalClientId)
{
CombatStats combatStats = Window.Snapshot(Time.unscaledTime);
return ModChannels.FormatDps(combatStats.Max, combatStats.Kills, false);
}
if (!Instance.TryGetRemoteStats(clientId, out var stats, out var dpsEstimated, out var _))
{
return null;
}
return ModChannels.FormatDps(stats.Max, stats.Kills, dpsEstimated || !stats.TotalsKnown);
}
catch
{
return null;
}
}
internal bool TryGetRemoteStats(ulong clientId, out CombatStats stats, out bool dpsEstimated, out bool totalsEstimated)
{
CombatStats stats2;
bool flag = Estimates.TryGet(clientId, Time.unscaledTime, out stats2);
if (network.TryGet(clientId, out stats))
{
dpsEstimated = false;
totalsEstimated = !stats.TotalsKnown || !stats.DamageKnown;
if (totalsEstimated && flag)
{
stats.Max = Math.Max(stats.Max, stats2.Max);
if (!stats.TotalsKnown)
{
stats.Kills = stats2.Kills;
}
if (!stats.DamageKnown)
{
stats.TotalDamage = stats2.TotalDamage;
}
}
return true;
}
dpsEstimated = true;
totalsEstimated = true;
stats = stats2;
return flag;
}
private static void OnEnemyDamageServer(EnemyPart __instance, DamageData data, IDamageSource source)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
RecordEstimate((NetworkBehaviour)(object)__instance, data, source, client: false);
}
private static void OnObjectDamageServer(ObjectTarget __instance, DamageData data, IDamageSource source)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
if (__instance is DynamicTrainingTarget)
{
RecordEstimate((NetworkBehaviour)(object)__instance, data, source, client: false);
}
}
private static void OnEnemyKillServer(EnemyPart __instance, IDamageSource source)
{
EnemyCore val = (EnemyCore)(object)((__instance is EnemyCore) ? __instance : null);
if ((Object)(object)val != (Object)null && ((EnemyPart)val).IsAlive)
{
RecordEstimatedKill(val, source);
}
}
private static void OnEnemyKillRpc(NetworkBehaviour target, FastBufferReader reader)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
try
{
EnemyCore val = (EnemyCore)(object)((target is EnemyCore) ? target : null);
if (!((Object)(object)val == (Object)null) && !((NetworkBehaviour)val).IsServer && ((NetworkBehaviour)val).IsClient)
{
NetworkBehaviourReference val2 = DamageRpcReader.ReadKillSource(reader);
NetworkBehaviour val3 = default(NetworkBehaviour);
RecordEstimatedKill(val, (IDamageSource)(object)(((NetworkBehaviourReference)(ref val2)).TryGet(ref val3, (NetworkManager)null) ? ((val3 is IDamageSource) ? val3 : null) : null));
}
}
catch (Exception e)
{
LogEstimateError(e);
}
}
private static void RecordEstimatedKill(EnemyCore core, IDamageSource source)
{
try
{
if (!((Object)(object)Instance == (Object)null) && source != null && !EstimatedKills.Contains(core))
{
Player val = AttackerResolver.Resolve(source);
if (!((Object)(object)val == (Object)null) && !((NetworkBehaviour)val).IsLocalPlayer)
{
EstimatedKills.Add(core);
Estimates.AddKill(((NetworkBehaviour)val).OwnerClientId);
}
}
}
catch (Exception e)
{
LogEstimateError(e);
}
}
private static void OnNetworkVariablesInitialized(NetworkBehaviour __instance)
{
if ((Object)(object)Instance != (Object)null && Instance.damageRpcHooks != null && (__instance is EnemyPart || __instance is DynamicTrainingTarget))
{
Instance.damageRpcHooks.Install(((object)__instance).GetType());
}
}
private static void OnEnemyDamageRpc(NetworkBehaviour __0, FastBufferReader __1)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((__0 is EnemyPart || __0 is DynamicTrainingTarget) && !__0.IsServer && __0.IsClient)
{
if (!estimateRpcLogged && (Object)(object)Instance != (Object)null)
{
estimateRpcLogged = true;
((BaseUnityPlugin)Instance).Logger.LogInfo((object)"DPS estimate: received a target damage RPC.");
}
DamageRpcReader.Read(__1, out var damage, out var source);
NetworkBehaviour val = default(NetworkBehaviour);
IDamageSource source2 = (IDamageSource)(object)(((NetworkBehaviourReference)(ref source)).TryGet(ref val, (NetworkManager)null) ? ((val is IDamageSource) ? val : null) : null);
RecordEstimate(__0, damage, source2, client: true);
}
}
catch (Exception e)
{
LogEstimateError(e);
}
}
private static void RecordEstimate(NetworkBehaviour target, DamageData data, IDamageSource source, bool client)
{
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
try
{
ITarget val = (ITarget)(object)((target is ITarget) ? target : null);
if ((Object)(object)Instance == (Object)null || (Object)(object)target == (Object)null || val == null || !val.IsAlive || (client && target.IsHost))
{
return;
}
if (!estimateEventLogged)
{
estimateEventLogged = true;
((BaseUnityPlugin)Instance).Logger.LogInfo((object)"DPS estimate: received a target damage event.");
}
if (source == null)
{
if (!estimateMissingSourceLogged)
{
((BaseUnityPlugin)Instance).Logger.LogInfo((object)"DPS estimate: an event had no networked damage source.");
}
estimateMissingSourceLogged = true;
return;
}
Player val2 = AttackerResolver.Resolve(source);
if ((Object)(object)val2 == (Object)null)
{
if (!estimateUnknownSourceLogged)
{
((BaseUnityPlugin)Instance).Logger.LogInfo((object)("DPS estimate: could not match a damage source to a player (" + ((object)source).GetType().Name + ")."));
}
estimateUnknownSourceLogged = true;
}
else if (!((NetworkBehaviour)val2).IsLocalPlayer)
{
Estimates.Add(((NetworkBehaviour)val2).OwnerClientId, Time.unscaledTime, data.damage);
if (data.damage > 0f && !float.IsNaN(data.damage) && !float.IsInfinity(data.damage) && !estimateSuccessLogged)
{
estimateSuccessLogged = true;
((BaseUnityPlugin)Instance).Logger.LogInfo((object)"DPS estimate: recorded teammate damage.");
}
}
}
catch (Exception e)
{
LogEstimateError(e);
}
}
internal void LogEstimateDisplay()
{
if (!estimateDisplayLogged)
{
estimateDisplayLogged = true;
((BaseUnityPlugin)this).Logger.LogInfo((object)"DPS estimate: displayed a teammate estimate on the HUD.");
}
}
private static void LogEstimateError(Exception e)
{
if (!estimateErrorLogged && (Object)(object)Instance != (Object)null)
{
estimateErrorLogged = true;
((BaseUnityPlugin)Instance).Logger.LogWarning((object)("DPS estimation missed a damage event: " + e));
}
}
private static void OnTeammateInitialize(TeammateHUD __instance, Player player)
{
TeammateDpsLabel teammateDpsLabel = null;
try
{
teammateDpsLabel = ((Component)__instance).GetComponent<TeammateDpsLabel>();
if ((Object)(object)teammateDpsLabel == (Object)null)
{
teammateDpsLabel = ((Component)__instance).gameObject.AddComponent<TeammateDpsLabel>();
}
if (!teammateDpsLabel.Initialize(__instance, player))
{
Object.Destroy((Object)(object)teammateDpsLabel);
if ((Object)(object)Instance != (Object)null)
{
((BaseUnityPlugin)Instance).Logger.LogWarning((object)"DPS teammate label could not be created (TeammateHUD fields not found).");
}
}
}
catch (Exception ex)
{
if ((Object)(object)teammateDpsLabel != (Object)null)
{
Object.Destroy((Object)(object)teammateDpsLabel);
}
if ((Object)(object)Instance != (Object)null)
{
((BaseUnityPlugin)Instance).Logger.LogWarning((object)("DPS teammate label could not be created: " + ex));
}
}
}
private void OnGUI()
{
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
Player localPlayer = Player.LocalPlayer;
if (ready && !((Object)(object)localPlayer == (Object)null) && !localLabel.Visible)
{
GUI.Box(new Rect(20f, 20f, 420f, 44f), GUIContent.none);
GUI.Label(new Rect(30f, 28f, 400f, 24f), fallbackText.Get(Window.Snapshot(Time.unscaledTime), dpsEstimated: false, totalsEstimated: false, local: true));
}
}
}
internal sealed class RemoteDps
{
private struct Sample
{
public CombatStats Value;
public float Time;
}
private readonly Dictionary<ulong, Sample> values = new Dictionary<ulong, Sample>();
public bool Set(ulong id, CombatStats value, float time)
{
if (value.Dps < 0f || float.IsNaN(value.Dps) || float.IsInfinity(value.Dps) || value.Max < 0f || float.IsNaN(value.Max) || float.IsInfinity(value.Max) || value.TotalDamage < 0f || float.IsNaN(value.TotalDamage) || float.IsInfinity(value.TotalDamage) || value.Kills < 0)
{
return false;
}
if (!value.TotalsKnown && values.TryGetValue(id, out var value2))
{
value.Max = Math.Max(value.Max, Math.Max(value2.Value.Max, value.Dps));
}
else if (!value.TotalsKnown)
{
value.Max = Math.Max(value.Max, value.Dps);
}
values[id] = new Sample
{
Value = value,
Time = time
};
return true;
}
public bool TryGet(ulong id, float time, out CombatStats value)
{
if (values.TryGetValue(id, out var value2) && time - value2.Time < 3f)
{
value = value2.Value;
return true;
}
value = default(CombatStats);
return false;
}
public void Remove(ulong id)
{
values.Remove(id);
}
public void Clear()
{
values.Clear();
}
}
public sealed class TeammateDpsLabel : MonoBehaviour
{
internal const string LineId = "f1w3.dpschecker";
internal const int LineOrder = 100;
private static readonly TeammateDpsText.StatsSource FromPlugin = delegate(ulong id, out CombatStats stats, out bool dpsEstimated, out bool totalsEstimated)
{
stats = default(CombatStats);
dpsEstimated = (totalsEstimated = true);
return (Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.TryGetRemoteStats(id, out stats, out dpsEstimated, out totalsEstimated);
};
private Player player;
private TeammateHUD owner;
private TextMeshProUGUI nameText;
private TextMeshProUGUI label;
private float nextUpdate;
private readonly TeammateDpsText text = new TeammateDpsText(FromPlugin, delegate
{
if ((Object)(object)Plugin.Instance != (Object)null)
{
Plugin.Instance.LogEstimateDisplay();
}
});
internal bool Initialize(TeammateHUD hud, Player teammate)
{
owner = hud;
player = teammate;
nameText = hud.nameText;
label = UnityTeammateHud.AddText(hud, "f1w3.dpschecker", 100);
if ((Object)(object)label == (Object)null || (Object)(object)nameText == (Object)null)
{
return false;
}
nextUpdate = 0f;
Refresh();
return true;
}
private void Update()
{
if (!(Time.unscaledTime < nextUpdate))
{
nextUpdate = Time.unscaledTime + 0.25f;
Refresh();
}
}
private void Refresh()
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)label == (Object)null) && !((Object)(object)nameText == (Object)null) && !((Object)(object)player == (Object)null))
{
string text = this.text.Get(((NetworkBehaviour)player).OwnerClientId);
GameHudText.SetText(label, text);
((Graphic)label).color = ((Graphic)nameText).color;
((TMP_Text)label).fontSize = ((TMP_Text)nameText).fontSize;
UnityTeammateHud.Place(owner);
}
}
private void OnDestroy()
{
if ((Object)(object)owner != (Object)null)
{
UnityTeammateHud.Remove(owner, "f1w3.dpschecker");
}
}
}
internal sealed class TeammateDpsText
{
internal delegate bool StatsSource(ulong clientId, out CombatStats stats, out bool dpsEstimated, out bool totalsEstimated);
private readonly StatsSource source;
private readonly Action estimateShown;
private readonly StatsText text = new StatsText();
public TeammateDpsText(StatsSource source, Action estimateShown)
{
this.source = source;
this.estimateShown = estimateShown;
}
public string Get(ulong clientId)
{
if (!source(clientId, out var stats, out var dpsEstimated, out var totalsEstimated))
{
stats = default(CombatStats);
dpsEstimated = (totalsEstimated = true);
}
else if (dpsEstimated && estimateShown != null)
{
estimateShown();
}
return text.Get(stats, dpsEstimated, totalsEstimated);
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}