using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GameData;
using Gear;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SquadUI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SquadUI")]
[assembly: AssemblyTitle("SquadUI")]
[assembly: AssemblyVersion("1.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;
}
}
}
namespace SquadUI
{
public static class SquadUIArmor
{
private static readonly Dictionary<int, float> s_rel = new Dictionary<int, float>();
public static void Set(int slot, float relative01)
{
try
{
if (slot < 0)
{
slot = PlayerManager.GetLocalPlayerSlotIndex();
}
if (slot >= 0)
{
s_rel[slot] = ((relative01 < 0f) ? 0f : ((relative01 > 1f) ? 1f : relative01));
}
}
catch
{
}
}
public static void Clear(int slot)
{
try
{
s_rel.Remove(slot);
}
catch
{
}
}
public static void ClearAll()
{
try
{
s_rel.Clear();
}
catch
{
}
}
internal static bool TryGet(int slot, out float rel)
{
return s_rel.TryGetValue(slot, out rel);
}
}
public class HudBehaviour : MonoBehaviour
{
private static int s_lastFrame = -1;
private static bool s_tickLogged;
private static bool s_guiLogged;
private static float s_nextCapture;
private static float s_warnAt = -999f;
private static HudSkin s_skin;
private static readonly List<MemberView> s_rows = new List<MemberView>();
private static readonly List<float> s_rowH = new List<float>();
private static float s_guiMs;
private static int s_guiFrames;
private static float s_nextPerfLog;
private static bool s_offsetDirty;
private static float s_offsetDirtyAt;
private void Update()
{
OnTick();
}
internal static void OnTick()
{
try
{
int frameCount = Time.frameCount;
if (frameCount == s_lastFrame)
{
return;
}
s_lastFrame = frameCount;
if (!s_tickLogged)
{
s_tickLogged = true;
Plugin.LogSource.LogInfo((object)"[hud] 数据采集已启动。");
}
HudSettings settings = Plugin.Settings;
if (settings == null)
{
return;
}
HandleKeys(settings);
if (settings.Enabled.Value)
{
float num = Mathf.Clamp(settings.UpdateHz.Value, 2f, 60f);
float unscaledTime = Time.unscaledTime;
if (unscaledTime >= s_nextCapture)
{
s_nextCapture = unscaledTime + 1f / num;
SquadReader.Capture();
}
}
PerfLog(settings);
}
catch (Exception e)
{
Warn("tick", e);
}
}
private static void HandleKeys(HudSettings s)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
try
{
string value = s.ToggleKey.Value;
if (!string.IsNullOrEmpty(value) && Enum.TryParse<KeyCode>(value, ignoreCase: true, out KeyCode result) && Input.GetKeyDown(result))
{
s.Enabled.Value = !s.Enabled.Value;
try
{
((ConfigEntryBase)s.Enabled).ConfigFile.Save();
}
catch
{
}
Plugin.LogSource.LogInfo((object)("[hud] 小队面板 " + (s.Enabled.Value ? "开" : "关")));
}
if (!s.MoveWithArrows.Value || (!Input.GetKey((KeyCode)306) && !Input.GetKey((KeyCode)305)))
{
return;
}
float num = 0f;
float num2 = 0f;
if (Input.GetKey((KeyCode)276))
{
num -= 1f;
}
if (Input.GetKey((KeyCode)275))
{
num += 1f;
}
if (Input.GetKey((KeyCode)273))
{
num2 -= 1f;
}
if (Input.GetKey((KeyCode)274))
{
num2 += 1f;
}
if (num != 0f || num2 != 0f)
{
float num3 = Mathf.Max(20f, s.MoveSpeed.Value) * Time.unscaledDeltaTime;
s.OffsetX.Value = Mathf.Clamp(s.OffsetX.Value + num * num3, -400f, 4000f);
s.OffsetY.Value = Mathf.Clamp(s.OffsetY.Value + num2 * num3, -400f, 3000f);
s_offsetDirty = true;
s_offsetDirtyAt = Time.unscaledTime;
}
else if (s_offsetDirty && Time.unscaledTime - s_offsetDirtyAt > 1f)
{
s_offsetDirty = false;
try
{
((ConfigEntryBase)s.OffsetX).ConfigFile.Save();
return;
}
catch
{
return;
}
}
}
catch
{
}
}
private void OnGUI()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Invalid comparison between Unknown and I4
try
{
if (!s_guiLogged)
{
s_guiLogged = true;
Plugin.LogSource.LogInfo((object)"[hud] 界面绘制已启动。");
}
HudSettings settings = Plugin.Settings;
if (settings == null)
{
return;
}
Event current = Event.current;
if (current == null || (int)current.type == 7)
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
EnsureSkin(settings);
GUI.depth = -1000;
bool flag = SquadReader.InLevel && SquadReader.Members.Count > 0;
if (settings.Enabled.Value && (flag || settings.AlwaysDraw.Value))
{
DrawSquadPanel(settings);
}
s_guiMs += (Time.realtimeSinceStartup - realtimeSinceStartup) * 1000f;
s_guiFrames++;
}
}
catch (Exception e)
{
Warn("gui", e);
}
}
private static void DrawSquadPanel(HudSettings s)
{
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: 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_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_0262: Unknown result type (might be due to invalid IL or missing references)
//IL_026c: Expected O, but got Unknown
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
//IL_03df: Expected O, but got Unknown
//IL_03da: Unknown result type (might be due to invalid IL or missing references)
//IL_0342: Unknown result type (might be due to invalid IL or missing references)
//IL_034c: Expected O, but got Unknown
//IL_0347: Unknown result type (might be due to invalid IL or missing references)
//IL_0585: Unknown result type (might be due to invalid IL or missing references)
//IL_0587: Unknown result type (might be due to invalid IL or missing references)
//IL_0589: Unknown result type (might be due to invalid IL or missing references)
//IL_05c9: Unknown result type (might be due to invalid IL or missing references)
//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
//IL_060d: Unknown result type (might be due to invalid IL or missing references)
//IL_060f: Unknown result type (might be due to invalid IL or missing references)
//IL_0611: Unknown result type (might be due to invalid IL or missing references)
//IL_0682: Unknown result type (might be due to invalid IL or missing references)
//IL_0684: Unknown result type (might be due to invalid IL or missing references)
//IL_0686: Unknown result type (might be due to invalid IL or missing references)
//IL_06c3: Unknown result type (might be due to invalid IL or missing references)
//IL_06c5: Unknown result type (might be due to invalid IL or missing references)
//IL_06c7: Unknown result type (might be due to invalid IL or missing references)
//IL_06ca: Unknown result type (might be due to invalid IL or missing references)
//IL_06cc: Unknown result type (might be due to invalid IL or missing references)
//IL_06f0: Unknown result type (might be due to invalid IL or missing references)
//IL_06f2: Unknown result type (might be due to invalid IL or missing references)
//IL_06f4: Unknown result type (might be due to invalid IL or missing references)
//IL_06f7: Unknown result type (might be due to invalid IL or missing references)
//IL_06f9: Unknown result type (might be due to invalid IL or missing references)
//IL_071d: Unknown result type (might be due to invalid IL or missing references)
//IL_071f: Unknown result type (might be due to invalid IL or missing references)
//IL_0721: Unknown result type (might be due to invalid IL or missing references)
//IL_0724: Unknown result type (might be due to invalid IL or missing references)
//IL_0726: Unknown result type (might be due to invalid IL or missing references)
//IL_0797: Unknown result type (might be due to invalid IL or missing references)
//IL_0799: Unknown result type (might be due to invalid IL or missing references)
//IL_079b: Unknown result type (might be due to invalid IL or missing references)
float num = Mathf.Clamp(s.SelfScale.Value, 0.6f, 2f);
float num2 = s.SelfBarW.Value * num;
float num3 = s.SelfBarH.Value * num;
float num4 = s.SelfRowGap.Value * num;
float num5 = s.SelfColGap.Value * num;
float num6 = num3 + num4;
float num7 = num6 * 4f - num4;
Color fill = Colors.Parse(s.SelfColArmor.Value, new Color(0.24f, 0.48f, 0.84f));
Color fill2 = Colors.Parse(s.SelfColInfection.Value, new Color(0.26f, 0.76f, 0.29f));
Color fill3 = Colors.Parse(s.SelfColHealth.Value, new Color(0.84f, 0.25f, 0.23f));
Color fill4 = Colors.Parse(s.SelfColStamina.Value, new Color(0.91f, 0.76f, 0.23f));
Color fill5 = Colors.Parse(s.SelfColWeapon.Value, new Color(0.31f, 0.85f, 0.48f));
Color fill6 = Colors.Parse(s.SelfColTool.Value, new Color(0.5f, 0.78f, 0.91f));
Color warnCol = Colors.Parse(s.ColorAmmoEmpty.Value, new Color(0.88f, 0.27f, 0.23f, 1f));
Color readyCol = Colors.Parse(s.ColorPhaseReady.Value, new Color(0.31f, 0.85f, 0.48f, 1f));
Color fill7 = Colors.Parse(s.ColorMeleeCharge.Value, new Color(1f, 0.6f, 0.23f, 1f));
Color bg = Colors.Parse(s.SelfBarBg.Value, new Color(1f, 1f, 1f, 0.95f));
Color border = default(Color);
((Color)(ref border))..ctor(1f, 1f, 1f, 0.35f);
float num8 = s.SelfLabelW.Value * num;
try
{
string[] array = new string[4] { "护甲 100%", "感染 100%", "血量 100%", "体力 100%" };
float num9 = 0f;
for (int i = 0; i < array.Length; i++)
{
float x = s_skin.Small.CalcSize(new GUIContent(array[i])).x;
if (x > num9)
{
num9 = x;
}
}
num8 += num9 + 8f;
}
catch
{
}
float num10 = s.SelfNameW.Value * num;
try
{
float num11 = 0f;
for (int j = 0; j < SquadReader.Members.Count; j++)
{
MemberView memberView = SquadReader.Members[j];
string text = ((memberView.Tool != null && !string.IsNullOrEmpty(memberView.Tool.Name)) ? ToolLabel(memberView.Tool.Name) : "工具");
string[] array2 = new string[4]
{
"主武器 100%",
"特殊武器 100%",
text + " 100%",
"蓄力 100% 0.0s"
};
for (int k = 0; k < array2.Length; k++)
{
float x2 = s_skin.Small.CalcSize(new GUIContent(array2[k])).x;
if (x2 > num11)
{
num11 = x2;
}
}
}
num10 += num11 + 8f;
}
catch
{
}
float num12 = 0f;
try
{
for (int l = 0; l < SquadReader.Members.Count; l++)
{
string name = SquadReader.Members[l].Name;
if (string.IsNullOrEmpty(name))
{
continue;
}
for (int m = 0; m < name.Length; m++)
{
float x3 = s_skin.Small.CalcSize(new GUIContent(name.Substring(m, 1))).x;
if (x3 > num12)
{
num12 = x3;
}
}
}
num12 += 8f;
}
catch
{
}
float value = s.OffsetX.Value;
float num13 = s.OffsetY.Value;
for (int n = 0; n < SquadReader.Members.Count; n++)
{
MemberView memberView2 = SquadReader.Members[n];
if ((s.ShowSelf.Value || !memberView2.IsLocal) && (s.ShowDead.Value || memberView2.Alive))
{
float num14 = value + num12;
float x4 = num14 + num2 + num8 + num5;
s_skin.Small.normal.textColor = memberView2.Color;
string text2 = (string.IsNullOrEmpty(memberView2.Name) ? "?" : memberView2.Name);
float num15 = (float)s_skin.Small.fontSize + 8f;
int num16 = Mathf.Max(1, Mathf.FloorToInt(num7 / num15));
int num17 = Mathf.Min(text2.Length, num16);
float num18 = num13 + Mathf.Max(0f, (num7 - (float)num17 * num15) * 0.5f);
for (int num19 = 0; num19 < num17; num19++)
{
TextInBar(value, num18 + (float)num19 * num15, num12, num15, text2.Substring(num19, 1));
}
float rel = (memberView2.HasArmor ? memberView2.ArmorRel : 0f);
SelfRow(num14, num13 + 0f * num6, num2, num3, num8, rel, fill, bg, border, "护甲", Pct01(rel), null);
float rel2 = (memberView2.HasInfection ? memberView2.Infection : 0f);
SelfRow(num14, num13 + 1f * num6, num2, num3, num8, rel2, fill2, bg, border, "感染", Pct01(rel2), null);
float rel3 = (memberView2.HasDamage ? memberView2.HealthRel : 0f);
SelfRow(num14, num13 + 2f * num6, num2, num3, num8, rel3, fill3, bg, border, "血量", Pct01(rel3), null);
float rel4 = (memberView2.HasStamina ? memberView2.StaminaRel : 0f);
string inner = (memberView2.HasStamina ? (Mathf.RoundToInt(memberView2.Bpm) + " ♥") : "--");
SelfRow(num14, num13 + 3f * num6, num2, num3, num8, rel4, fill4, bg, border, "体力", memberView2.HasStamina ? Pct01(rel4) : "--", inner);
WeaponRow(x4, num13 + 0f * num6, num2, num3, num10, memberView2.Standard, fill5, bg, border, isTool: false, warnCol, readyCol, "主武器");
WeaponRow(x4, num13 + 1f * num6, num2, num3, num10, memberView2.Special, fill5, bg, border, isTool: false, warnCol, readyCol, "特殊武器");
WeaponRow(x4, num13 + 2f * num6, num2, num3, num10, memberView2.Tool, fill6, bg, border, isTool: true, warnCol, readyCol, null);
float meleeChargeRel = memberView2.MeleeChargeRel;
string value2 = ((memberView2.MeleeChargeNeed > 0.01f) ? (Mathf.RoundToInt(Mathf.Clamp01(meleeChargeRel) * 100f) + "% " + One(memberView2.MeleeChargeNeed) + "s") : "--");
SelfRow(x4, num13 + 3f * num6, num2, num3, num10, meleeChargeRel, fill7, bg, border, "蓄力", value2, null);
num13 += num7 + num4 * 2f;
}
}
}
private static void EnsureSkin(HudSettings s)
{
int num = Mathf.Clamp(s.BaseFontSize.Value, 8, 28);
string text = s.FontName.Value ?? "";
if (s_skin == null || !s_skin.Ready || s_skin.Size != num || !string.Equals(s_skin.FontName, text))
{
s_skin = HudSkin.Build(num, text);
}
}
private static string Fit(string s, int max)
{
if (string.IsNullOrEmpty(s))
{
return "?";
}
if (s.Length <= max)
{
return s;
}
return s.Substring(0, Mathf.Max(1, max - 1)) + "~";
}
private static string Two(float v)
{
int num = Mathf.RoundToInt(v * 100f);
return num / 100 + "." + num / 10 % 10 + num % 10;
}
private static void PerfLog(HudSettings s)
{
try
{
if (s != null && s.PerfLog.Value)
{
float unscaledTime = Time.unscaledTime;
if (!(unscaledTime < s_nextPerfLog))
{
s_nextPerfLog = unscaledTime + 1f;
float v = ((s_guiFrames > 0) ? (s_guiMs / (float)s_guiFrames) : 0f);
Plugin.LogSource.LogInfo((object)("[perf] capture=" + Two(SquadReader.MsCapture) + "ms scan峰值=" + Two(SquadReader.MsScanMax) + "ms ongui=" + Two(v) + "ms/帧(" + s_guiFrames + "帧) members=" + SquadReader.LastMemberCount + " placed=" + SquadReader.PlacedCount));
SquadReader.MsScanMax = 0f;
s_guiMs = 0f;
s_guiFrames = 0;
}
}
}
catch
{
}
}
private static string Pct01(float rel)
{
return Mathf.RoundToInt(Mathf.Clamp01(rel) * 100f) + "%";
}
private static string ToolLabel(string itemName)
{
if (string.IsNullOrEmpty(itemName))
{
return "--";
}
if (itemName.Contains("Optron"))
{
return "扫描";
}
if (itemName.Contains("Krieger"))
{
return "布雷";
}
if (itemName.Contains("Stalwart"))
{
return "胶沫";
}
if (itemName.Contains("SGB3"))
{
return "连发炮台";
}
if (itemName.Contains("Meduza"))
{
return "hel炮台";
}
if (itemName.Contains("51 RSG"))
{
return "狙击炮台";
}
if (itemName.Contains("B5 LFR"))
{
return "霰弹炮台";
}
return itemName;
}
private static void TextAt(float x, float y, float w, float h, string text)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
GUI.Label(new Rect(x, y, w, h), text, s_skin.Small);
}
private static void TextInBar(float x, float y, float w, float barH, string text)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
float num = (float)s_skin.Small.fontSize + 8f;
GUI.Label(new Rect(x, y + (barH - num) * 0.5f, w, num), text, s_skin.Small);
}
private static void SelfRow(float x, float y, float w, float h, float labW, float rel, Color fill, Color bg, Color border, string label, string value, string inner)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
HudSkin.Bar(new Rect(x, y, w, h), rel, fill, bg, border);
s_skin.Small.normal.textColor = new Color(0.05f, 0.05f, 0.06f, 1f);
if (!string.IsNullOrEmpty(inner))
{
TextInBar(x + 4f, y, w - 8f, h, inner);
}
s_skin.Small.normal.textColor = fill;
TextInBar(x + w + 6f, y, labW, h, label + " " + value);
}
private static void WeaponRow(float x, float y, float w, float h, float nameW, AmmoView a, Color fill, Color bg, Color border, bool isTool, Color warnCol, Color readyCol, string fixedName)
{
//IL_002d: 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_0037: 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)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: 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_0031: 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_0186: Unknown result type (might be due to invalid IL or missing references)
float rel = a?.Rel ?? 0f;
Color val = ((a != null && a.PhaseWarn) ? warnCol : ((a != null && a.PhaseReady) ? readyCol : fill));
HudSkin.Bar(new Rect(x, y, w, h), rel, val, bg, border);
string text = ((a != null) ? a.Text() : "--");
if (isTool && text.StartsWith("炮台"))
{
int num = text.IndexOf(' ');
if (num > 0)
{
text = text.Substring(num + 1);
}
}
s_skin.Small.normal.textColor = new Color(0.05f, 0.05f, 0.06f, 1f);
TextInBar(x + 4f, y, w - 8f, h, text);
string text2 = ((a != null && !string.IsNullOrEmpty(a.Name)) ? a.Name : "");
string text3 = ((!string.IsNullOrEmpty(fixedName)) ? fixedName : (isTool ? ToolLabel(text2) : ((text2.Length > 0) ? text2 : "--")));
string text4 = "";
if (a != null && a.Present)
{
if (!isTool)
{
text4 = " " + Pct01(a.RelPercent);
}
else if (!a.NoAmmo && a.PackMax > 0)
{
text4 = " " + Pct01(a.PackRel);
}
}
s_skin.Small.normal.textColor = val;
TextInBar(x + w + 6f, y, nameW, h, text3 + text4);
}
private static string One(float v)
{
int num = Mathf.RoundToInt(v * 10f);
return num / 10 + "." + Mathf.Abs(num % 10);
}
private static void Warn(string where, Exception e)
{
float unscaledTime = Time.unscaledTime;
if (unscaledTime - s_warnAt < 5f)
{
return;
}
s_warnAt = unscaledTime;
try
{
Plugin.LogSource.LogWarning((object)("[hud] " + where + " failed: " + e.GetType().Name + ": " + e.Message));
}
catch
{
}
}
}
public sealed class HudSettings
{
public ConfigEntry<bool> Enabled;
public ConfigEntry<bool> AlwaysDraw;
public ConfigEntry<float> UpdateHz;
public ConfigEntry<bool> ProbeLog;
public ConfigEntry<bool> AmmoDump;
public ConfigEntry<bool> PerfLog;
public ConfigEntry<bool> RemoteScannerPhase;
public ConfigEntry<string> ToggleKey;
public ConfigEntry<bool> MoveWithArrows;
public ConfigEntry<float> MoveSpeed;
public ConfigEntry<float> SelfX;
public ConfigEntry<float> SelfY;
public ConfigEntry<float> SelfScale;
public ConfigEntry<float> SelfBarW;
public ConfigEntry<float> SelfBarH;
public ConfigEntry<float> SelfRowGap;
public ConfigEntry<float> SelfLabelW;
public ConfigEntry<float> SelfColGap;
public ConfigEntry<float> SelfNameW;
public ConfigEntry<string> SelfColArmor;
public ConfigEntry<string> SelfColInfection;
public ConfigEntry<string> SelfColHealth;
public ConfigEntry<string> SelfColStamina;
public ConfigEntry<string> SelfColWeapon;
public ConfigEntry<string> SelfColTool;
public ConfigEntry<string> SelfBarBg;
public ConfigEntry<string> Anchor;
public ConfigEntry<float> OffsetX;
public ConfigEntry<float> OffsetY;
public ConfigEntry<float> Scale;
public ConfigEntry<float> Opacity;
public ConfigEntry<float> PanelWidth;
public ConfigEntry<string> FontName;
public ConfigEntry<int> BaseFontSize;
public ConfigEntry<bool> ShowSelf;
public ConfigEntry<bool> ShowDead;
public ConfigEntry<bool> ShowHealth;
public ConfigEntry<bool> ShowInfection;
public ConfigEntry<bool> ShowStamina;
public ConfigEntry<bool> ShowHeartbeat;
public ConfigEntry<bool> ShowAmmo;
public ConfigEntry<bool> ShowSelfDetail;
public ConfigEntry<bool> ShowMelee;
public ConfigEntry<bool> ShowCarry;
public ConfigEntry<bool> ShowPocket;
public ConfigEntry<string> ColorPanel;
public ConfigEntry<string> ColorText;
public ConfigEntry<string> ColorHealthGood;
public ConfigEntry<string> ColorHealthBad;
public ConfigEntry<string> ColorStamina;
public ConfigEntry<string> ColorInfection;
public ConfigEntry<string> ColorAmmo;
public ConfigEntry<string> ColorAmmoEmpty;
public ConfigEntry<string> ColorMeleeCharge;
public ConfigEntry<string> ColorPhaseReady;
private static ConfigDescription Choice(params string[] values)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
return new ConfigDescription("", (AcceptableValueBase)(object)new AcceptableValueList<string>(values), Array.Empty<object>());
}
public static HudSettings Bind(ConfigFile cfg)
{
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Expected O, but got Unknown
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Expected O, but got Unknown
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Expected O, but got Unknown
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Expected O, but got Unknown
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Expected O, but got Unknown
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Expected O, but got Unknown
//IL_0212: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Expected O, but got Unknown
//IL_0261: Unknown result type (might be due to invalid IL or missing references)
//IL_026b: Expected O, but got Unknown
HudSettings hudSettings = new HudSettings();
hudSettings.Enabled = cfg.Bind<bool>("1-General", "Enabled", true, "总开关。");
hudSettings.AlwaysDraw = cfg.Bind<bool>("1-General", "AlwaysDraw", true, "没有关卡数据时也显示面板(例如在标题界面)。进关卡后不影响显示。");
hudSettings.UpdateHz = cfg.Bind<float>("1-General", "UpdateHz", 15f, new ConfigDescription("每秒采集多少次队友数据。15 足够顺滑且几乎无开销。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>()));
hudSettings.ProbeLog = cfg.Bind<bool>("1-General", "ProbeLog", false, "详细日志:每秒把读取到的队友数据写一行到 BepInEx 日志。");
hudSettings.AmmoDump = cfg.Bind<bool>("1-General", "AmmoDump", false, "详细日志:每秒输出各槽位的弹药字段(AmmoInPack/AmmoMaxCap/BulletsInPack/CostOfBullet/GetClassAmmoInPackAbs…)。用来校正工具弹药口径,确认后我会关掉默认值。");
hudSettings.Anchor = cfg.Bind<string>("2-Layout", "Anchor", "BottomRight", new ConfigDescription("状态栏吸附在屏幕哪个角。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "TopLeft", "TopRight", "BottomLeft", "BottomRight" }), Array.Empty<object>()));
hudSettings.OffsetX = cfg.Bind<float>("2-Layout", "OffsetX", 18f, new ConfigDescription("距屏幕边缘的水平像素。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1200f), Array.Empty<object>()));
hudSettings.OffsetY = cfg.Bind<float>("2-Layout", "OffsetY", 150f, new ConfigDescription("距屏幕边缘的垂直像素(底部吸附时是离底距离)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1200f), Array.Empty<object>()));
hudSettings.Scale = cfg.Bind<float>("2-Layout", "Scale", 1f, new ConfigDescription("整体缩放。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.6f, 2.5f), Array.Empty<object>()));
hudSettings.Opacity = cfg.Bind<float>("2-Layout", "Opacity", 0.85f, new ConfigDescription("面板背景不透明度(文字不受影响)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
hudSettings.PanelWidth = cfg.Bind<float>("2-Layout", "PanelWidth", 470f, new ConfigDescription("面板宽度(未缩放像素)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(300f, 900f), Array.Empty<object>()));
hudSettings.FontName = cfg.Bind<string>("2-Layout", "FontName", "Microsoft YaHei", "IMGUI 动态字体名;留空则用游戏默认字体(默认字体不含中文)。");
hudSettings.BaseFontSize = cfg.Bind<int>("2-Layout", "BaseFontSize", 13, new ConfigDescription("基准字号。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 28), Array.Empty<object>()));
hudSettings.ShowSelf = cfg.Bind<bool>("3-Content", "ShowSelf", true, "状态栏里是否也显示自己。");
hudSettings.ShowDead = cfg.Bind<bool>("3-Content", "ShowDead", true, "是否显示已阵亡的队友。");
hudSettings.ShowHealth = cfg.Bind<bool>("3-Content", "ShowHealth", true, "显示血量条。");
hudSettings.ShowInfection = cfg.Bind<bool>("3-Content", "ShowInfection", true, "显示感染度。");
hudSettings.ShowStamina = cfg.Bind<bool>("3-Content", "ShowStamina", true, "显示体力(心跳)条。");
hudSettings.ShowHeartbeat = cfg.Bind<bool>("3-Content", "ShowHeartbeat", true, "在体力条上显示估算心跳 BPM。");
hudSettings.ShowAmmo = cfg.Bind<bool>("3-Content", "ShowAmmo", true, "显示主武器/特殊武器/工具弹药(弹匣/备弹)。");
hudSettings.ShowSelfDetail = cfg.Bind<bool>("3-Content", "ShowSelfDetail", true, "显示自己的近战武器与随身资源包详情块。");
hudSettings.ShowMelee = cfg.Bind<bool>("3-Content", "ShowMelee", true, "详情块里显示近战武器(名称 + 蓄力)。");
hudSettings.ShowCarry = cfg.Bind<bool>("3-Content", "ShowCarry", true, "每个队友各占一行显示他身上的资源包/消耗品种类与数量(不是只显示自己)。");
hudSettings.ShowPocket = cfg.Bind<bool>("3-Content", "ShowPocket", true, "详情块里显示口袋物品(物品 ID + 数量)。");
hudSettings.RemoteScannerPhase = cfg.Bind<bool>("3-Content", "RemoteScannerPhase", false, "队友(真人)的探测器是否也显示 准备/冷却/就绪。默认关闭:开着可能显示错误的冷却。有真人队友时可以打开试,若数字不对就报给我。");
hudSettings.ToggleKey = cfg.Bind<string>("1-General", "ToggleKey", "F9", "小队面板的开关热键(KeyCode 名,如 F9 / F10 / Insert)。按一下切换显示,会自动存回本文件。");
hudSettings.MoveWithArrows = cfg.Bind<bool>("1-General", "MoveWithArrows", true, "是否用 **Ctrl + 方向键** 移动小队面板(按住即移动,松手约 1 秒后自动存回本文件)。");
hudSettings.MoveSpeed = cfg.Bind<float>("1-General", "MoveSpeed", 240f, "方向键移动速度(像素/秒)。");
hudSettings.SelfX = cfg.Bind<float>("5-SelfPanel", "OffsetX", 12f, "距屏幕左边像素。");
hudSettings.SelfY = cfg.Bind<float>("5-SelfPanel", "OffsetY", 30f, "距屏幕上边像素。");
hudSettings.SelfScale = cfg.Bind<float>("5-SelfPanel", "Scale", 1f, "整体缩放 0.6–2.0。");
hudSettings.SelfBarW = cfg.Bind<float>("5-SelfPanel", "BarWidth", 130f, "条宽。");
hudSettings.SelfBarH = cfg.Bind<float>("5-SelfPanel", "BarHeight", 14f, "条高。");
hudSettings.SelfRowGap = cfg.Bind<float>("5-SelfPanel", "RowGap", 7f, "行间距。");
hudSettings.SelfLabelW = cfg.Bind<float>("5-SelfPanel", "LabelWidth", 0f, "第一列标签列的**额外留白**(列宽 = 文字实际宽度 + 这个值)。");
hudSettings.SelfColGap = cfg.Bind<float>("5-SelfPanel", "ColGap", 16f, "两列之间的额外间距。");
hudSettings.SelfNameW = cfg.Bind<float>("5-SelfPanel", "NameWidth", 0f, "第二列右侧「名字 + 百分号」的**额外留白**(同 LabelWidth)。");
hudSettings.SelfColArmor = cfg.Bind<string>("5-SelfPanel", "ColArmor", "#3E7BD6", "护甲条颜色。");
hudSettings.SelfColInfection = cfg.Bind<string>("5-SelfPanel", "ColInfection", "#43C24A", "感染条颜色。");
hudSettings.SelfColHealth = cfg.Bind<string>("5-SelfPanel", "ColHealth", "#D6403A", "血量条颜色。");
hudSettings.SelfColStamina = cfg.Bind<string>("5-SelfPanel", "ColStamina", "#E8C13A", "体力条 / 蓄力条颜色。");
hudSettings.SelfColWeapon = cfg.Bind<string>("5-SelfPanel", "ColWeapon", "#4FD97A", "主/特殊武器条颜色(绿)。");
hudSettings.SelfColTool = cfg.Bind<string>("5-SelfPanel", "ColTool", "#7FC7E8", "工具条颜色(蓝)。探测器不受此色影响(它用就绪绿/冷却红)。");
hudSettings.SelfBarBg = cfg.Bind<string>("5-SelfPanel", "BarBg", "#FFFFFF66", "条内「空」的底色。#RRGGBBAA,末两位是透明度 —— 66 约为四成白,压暗场景上看着是浅灰、黑字清楚。想更亮写 99/B0,想更暗写 40/33。");
hudSettings.PerfLog = cfg.Bind<bool>("1-General", "PerfLog", true, "性能日志:每秒打印一次采集/绘制耗时(ms)。不需要可以关掉。");
hudSettings.ColorPanel = cfg.Bind<string>("4-Colours", "Panel", "#0A0F14B8", "面板底色,#RRGGBB 或 #RRGGBBAA。");
hudSettings.ColorText = cfg.Bind<string>("5-Colours", "Text", "#E6F0F5FF", "主文字颜色。");
hudSettings.ColorHealthGood = cfg.Bind<string>("5-Colours", "HealthGood", "#4FD97AFF", "血量充足时的颜色。");
hudSettings.ColorHealthBad = cfg.Bind<string>("5-Colours", "HealthBad", "#E0453AFF", "血量危险时的颜色。");
hudSettings.ColorStamina = cfg.Bind<string>("5-Colours", "Stamina", "#F2C14EFF", "体力条颜色。");
hudSettings.ColorInfection = cfg.Bind<string>("5-Colours", "Infection", "#B06BE8FF", "感染度颜色。");
hudSettings.ColorAmmo = cfg.Bind<string>("5-Colours", "Ammo", "#57B8E8FF", "弹药条颜色。");
hudSettings.ColorAmmoEmpty = cfg.Bind<string>("5-Colours", "AmmoEmpty", "#E0453AFF", "弹药耗尽时的文字颜色。");
hudSettings.ColorMeleeCharge = cfg.Bind<string>("5-Colours", "MeleeCharge", "#FF9A3CFF", "近战蓄力条颜色。");
hudSettings.ColorPhaseReady = cfg.Bind<string>("5-Colours", "PhaseReady", "#4FD97AFF", "非弹药工具(生物探测器)**就绪**时的条颜色(冷却时固定用 AmmoEmpty 的红色)。");
return hudSettings;
}
}
internal sealed class HudSkin
{
internal bool Ready;
internal int Size;
internal string FontName;
internal Font Font;
internal GUIStyle Text;
internal GUIStyle Small;
internal GUIStyle Title;
internal GUIStyle Right;
internal static HudSkin Build(int size, string fontName)
{
HudSkin hudSkin = new HudSkin();
hudSkin.Size = size;
hudSkin.FontName = fontName;
try
{
if (!string.IsNullOrEmpty(fontName))
{
hudSkin.Font = Font.CreateDynamicFontFromOSFont(fontName, size);
}
}
catch
{
hudSkin.Font = null;
}
int size2 = Mathf.Max(8, size - 2);
hudSkin.Text = Make(size, (TextAnchor)3, hudSkin.Font);
hudSkin.Small = Make(size2, (TextAnchor)3, hudSkin.Font);
hudSkin.Title = Make(size, (TextAnchor)3, hudSkin.Font);
hudSkin.Title.fontStyle = (FontStyle)1;
hudSkin.Right = Make(size2, (TextAnchor)5, hudSkin.Font);
hudSkin.Ready = true;
return hudSkin;
}
private static GUIStyle Make(int size, TextAnchor anchor, Font font)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
GUIStyle val = new GUIStyle(GUI.skin.label);
val.fontSize = size;
val.alignment = anchor;
val.wordWrap = false;
val.richText = false;
if ((Object)(object)font != (Object)null)
{
val.font = font;
}
val.normal.textColor = Color.white;
return val;
}
internal static void Fill(Rect r, Color c)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: 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)
if (!(((Rect)(ref r)).width <= 0f) && !(((Rect)(ref r)).height <= 0f))
{
Color color = GUI.color;
GUI.color = c;
GUI.DrawTexture(r, (Texture)(object)Texture2D.whiteTexture);
GUI.color = color;
}
}
internal static void Bar(Rect r, float rel, Color fill, Color bg, Color border)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
Fill(new Rect(((Rect)(ref r)).x - 1f, ((Rect)(ref r)).y - 1f, ((Rect)(ref r)).width + 2f, ((Rect)(ref r)).height + 2f), border);
Fill(r, bg);
rel = Mathf.Clamp01(rel);
if (rel > 0.001f)
{
Fill(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, ((Rect)(ref r)).width * rel, ((Rect)(ref r)).height), fill);
}
}
}
internal static class Colors
{
internal static Color Parse(string hex, Color fallback)
{
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
if (string.IsNullOrEmpty(hex))
{
return fallback;
}
string text = hex.Trim();
if (text.Length > 0 && text[0] == '#')
{
text = text.Substring(1);
}
if (text.Length == 3)
{
text = text[0].ToString() + text[0] + text[1] + text[1] + text[2] + text[2];
}
if (text.Length == 6)
{
text += "FF";
}
if (text.Length != 8)
{
return fallback;
}
try
{
int num = Convert.ToInt32(text.Substring(0, 2), 16);
int num2 = Convert.ToInt32(text.Substring(2, 2), 16);
int num3 = Convert.ToInt32(text.Substring(4, 2), 16);
int num4 = Convert.ToInt32(text.Substring(6, 2), 16);
return new Color((float)num / 255f, (float)num2 / 255f, (float)num3 / 255f, (float)num4 / 255f);
}
catch
{
return fallback;
}
}
}
[BepInPlugin("mltz.squadui", "Squad UI", "1.0.0")]
public class Plugin : BasePlugin
{
public const string Guid = "mltz.squadui";
public const string Name = "Squad UI";
public const string Version = "1.0.0";
internal static Plugin Instance;
internal static ManualLogSource LogSource;
internal static HudSettings Settings;
public override void Load()
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
Instance = this;
LogSource = ((BasePlugin)this).Log;
Settings = HudSettings.Bind(((BasePlugin)this).Config);
try
{
((BasePlugin)this).AddComponent<HudBehaviour>();
}
catch (Exception ex)
{
LogSource.LogWarning((object)("[hud] 无法注入 HUD 组件:" + ex.Message));
}
ManualLogSource logSource = LogSource;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 7, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Squad UI");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(全队 UI)v");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.0");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded | 显示=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Settings.Enabled.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("开关热键=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Settings.ToggleKey.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" 方向键移动=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Settings.MoveWithArrows.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("缩放=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Settings.Scale.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" 采集=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Settings.UpdateHz.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Hz");
}
logSource.LogInfo(val);
LogSource.LogInfo((object)"[hud] 面板已就绪。");
}
public override bool Unload()
{
return true;
}
}
internal sealed class AmmoView
{
internal string Tag = "?";
internal string Name;
internal int Clip = -1;
internal int Pack;
internal int PackMax;
internal int ClipMax = -1;
internal bool Present;
internal bool Tool;
internal string PhaseText;
internal float PhaseRel = -1f;
internal bool PhaseWarn;
internal bool PhaseReady;
internal bool NoAmmo;
internal int OwnerSlot = -1;
internal float RelPercent;
internal float PackRel
{
get
{
if (PackMax <= 0)
{
return 0f;
}
return Mathf.Clamp01((float)Pack / (float)PackMax);
}
}
internal float Rel
{
get
{
if (!(PhaseRel >= 0f))
{
return PackRel;
}
return Mathf.Clamp01(PhaseRel);
}
}
internal string Text()
{
if (PhaseText != null)
{
return PhaseText;
}
if (!Present)
{
return "--";
}
if (Tool)
{
return Pack + "/" + PackMax;
}
if (ClipMax == 0)
{
return Pack + "/" + PackMax;
}
return ((Clip >= 0) ? Clip.ToString() : "--") + "/" + Pack + "/" + PackMax;
}
}
internal sealed class GearView
{
internal string Name;
internal int Amount = -1;
internal int AmountMax = -1;
internal bool IsResourcePack;
}
internal sealed class MemberView
{
internal int SlotIndex;
internal string Name = "?";
internal Color Color = Color.white;
internal bool IsLocal;
internal bool IsBot;
internal bool Alive = true;
internal string Error;
internal SNet_Player Player;
internal bool HasDamage;
internal float Health;
internal float HealthMax;
internal float HealthRel;
internal float Infection;
internal bool HasInfection;
internal bool HasArmor;
internal float ArmorRel;
internal bool HasStamina;
internal float Stamina;
internal float StaminaMax;
internal float StaminaRel;
internal bool IsTired;
internal AmmoView Standard = new AmmoView
{
Tag = "STD"
};
internal AmmoView Special = new AmmoView
{
Tag = "SPC"
};
internal AmmoView Tool = new AmmoView
{
Tag = "TOL"
};
internal string MeleeName;
internal string MeleeState;
internal bool MeleeCharging;
internal float MeleeChargeRel;
internal float MeleeChargeSeconds;
internal float MeleeChargeElapsed;
internal float MeleeChargeNeed;
internal bool ToolBusy;
internal string ToolBusyLabel;
internal readonly List<GearView> Carry = new List<GearView>();
internal readonly List<GearView> Pocket = new List<GearView>();
internal float Bpm;
}
internal static class SquadReader
{
private sealed class PlacedSentry
{
internal int Cur = -1;
internal int Max = -1;
}
internal static readonly List<MemberView> Members = new List<MemberView>();
internal static bool InLevel;
internal static string LastError;
internal static float MsCapture;
internal static float MsScan;
internal static float MsScanMax;
internal static int LastMemberCount;
private static readonly Dictionary<string, float> s_sentryCostByName = new Dictionary<string, float>();
private static readonly HashSet<string> s_sentryModels = new HashSet<string>();
private static readonly HashSet<string> s_scannerModels = new HashSet<string>();
private static bool s_memLoaded;
private static readonly Dictionary<int, PlayerBackpack> s_backpackBySlot = new Dictionary<int, PlayerBackpack>();
private static readonly Dictionary<int, float> s_deployedCheckedAt = new Dictionary<int, float>();
private static readonly Dictionary<uint, string> s_itemNameCache = new Dictionary<uint, string>();
private static float s_lastProbe;
private static readonly Dictionary<int, PlacedSentry> s_scanPlaced = new Dictionary<int, PlacedSentry>();
private static readonly Dictionary<string, PlacedSentry> s_scanByModel = new Dictionary<string, PlacedSentry>();
private static readonly List<SentryGunInstance> s_scanRefs = new List<SentryGunInstance>();
private static readonly List<int> s_scanSlots = new List<int>();
private static Type s_sentryType;
private static float s_nextSentryScan;
private static int s_scanMisses;
private static readonly Dictionary<int, string> s_deployedSlots = new Dictionary<int, string>();
private static float s_lastDump;
private static readonly Dictionary<int, float> s_lastMeleeNeed = new Dictionary<int, float>();
internal static int PlacedCount => s_scanPlaced.Count;
private static string SentryMemPath()
{
try
{
return Path.Combine(Paths.ConfigPath, "mltz.squadui.sentries.txt");
}
catch
{
return null;
}
}
private static void LoadSentryMemory()
{
if (s_memLoaded)
{
return;
}
s_memLoaded = true;
try
{
string text = SentryMemPath();
if (text == null || !File.Exists(text))
{
return;
}
string[] array = File.ReadAllLines(text);
foreach (string text2 in array)
{
if (string.IsNullOrEmpty(text2))
{
continue;
}
int num = text2.IndexOf('=');
if (num <= 0)
{
continue;
}
string text3 = text2.Substring(0, num).Trim();
string text4 = text2.Substring(num + 1).Trim();
float result;
if (text3 == "!scan")
{
if (!string.IsNullOrEmpty(text4))
{
s_scannerModels.Add(text4);
}
}
else if (!string.IsNullOrEmpty(text3) && float.TryParse(text4, NumberStyles.Float, CultureInfo.InvariantCulture, out result) && result > 0.0001f)
{
s_sentryCostByName[text3] = result;
s_sentryModels.Add(text3);
}
}
Plugin.LogSource.LogInfo((object)("[sentry] 已载入型号记忆:" + s_sentryCostByName.Count + " 个型号 -> " + (text ?? "?")));
}
catch (Exception ex)
{
Plugin.LogSource.LogWarning((object)("[sentry] 载入型号记忆失败:" + ex.Message));
}
}
private static void SaveSentryMemory()
{
try
{
string text = SentryMemPath();
if (text == null)
{
return;
}
List<string> list = new List<string>();
foreach (string s_scannerModel in s_scannerModels)
{
list.Add("!scan=" + s_scannerModel);
}
foreach (KeyValuePair<string, float> item in s_sentryCostByName)
{
list.Add(item.Key + "=" + item.Value.ToString("0.##########", CultureInfo.InvariantCulture));
}
File.WriteAllLines(text, list.ToArray());
}
catch (Exception ex)
{
Plugin.LogSource.LogWarning((object)("[sentry] 保存型号记忆失败:" + ex.Message));
}
}
private static string ArchKey(ArchetypeDataBlock arch)
{
if (arch == null)
{
return null;
}
return F(arch.CostOfBullet) + "|" + arch.DefaultClipSize + "|" + F(arch.Sentry_DetectionMaxRange) + "|" + F(arch.Sentry_DetectionMaxAngle);
}
private static void ScanPlacedSentry()
{
float unscaledTime = Time.unscaledTime;
for (int num = s_scanRefs.Count - 1; num >= 0; num--)
{
SentryGunInstance val = s_scanRefs[num];
bool flag = false;
try
{
flag = (Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null && ((Component)val).gameObject.activeInHierarchy;
}
catch
{
}
if (!flag)
{
s_scanRefs.RemoveAt(num);
if (num < s_scanSlots.Count)
{
s_scanSlots.RemoveAt(num);
}
}
}
s_scanPlaced.Clear();
s_scanByModel.Clear();
for (int i = 0; i < s_scanRefs.Count; i++)
{
SentryGunInstance val2 = s_scanRefs[i];
if ((Object)(object)val2 == (Object)null)
{
continue;
}
int num2 = ((i < s_scanSlots.Count) ? s_scanSlots[i] : (-1));
if (num2 < 0)
{
try
{
PlayerAgent owner = ((Item)val2).Owner;
if ((Object)(object)owner != (Object)null)
{
num2 = owner.PlayerSlotIndex;
if (i < s_scanSlots.Count)
{
s_scanSlots[i] = num2;
}
}
}
catch
{
}
}
float num3 = -1f;
float num4 = -1f;
float num5 = -1f;
try
{
num3 = val2.CostOfBullet;
}
catch
{
}
try
{
num4 = val2.Ammo;
}
catch
{
}
try
{
num5 = val2.AmmoMaxCap;
}
catch
{
}
if (num3 <= 0.0001f)
{
continue;
}
PlacedSentry placedSentry = new PlacedSentry();
placedSentry.Cur = ((num4 >= 0f) ? Mathf.FloorToInt(num4 / num3) : (-1));
placedSentry.Max = ((num5 >= 0f) ? Mathf.FloorToInt(num5 / num3) : (-1));
if (num2 >= 0)
{
s_scanPlaced[num2] = placedSentry;
}
try
{
string publicName = ((Item)val2).PublicName;
if (!string.IsNullOrEmpty(publicName) && publicName.IndexOf(' ') > 0)
{
s_scanByModel[publicName] = placedSentry;
float value;
bool num6 = !s_sentryCostByName.TryGetValue(publicName, out value) || Mathf.Abs(value - num3) > 0.0001f;
s_sentryCostByName[publicName] = num3;
s_sentryModels.Add(publicName);
if (num6)
{
SaveSentryMemory();
Plugin.LogSource.LogInfo((object)("[sentry] 记下型号成本:" + publicName + " = " + num3.ToString("0.##########", CultureInfo.InvariantCulture)));
}
}
}
catch
{
}
}
bool flag2 = false;
foreach (KeyValuePair<int, string> s_deployedSlot in s_deployedSlots)
{
if (!s_scanPlaced.TryGetValue(s_deployedSlot.Key, out var _) && (string.IsNullOrEmpty(s_deployedSlot.Value) || !s_scanByModel.ContainsKey(s_deployedSlot.Value)))
{
flag2 = true;
break;
}
}
if (flag2 && unscaledTime >= s_nextSentryScan)
{
s_scanMisses++;
float num7 = 3f;
for (int j = 1; j < s_scanMisses; j++)
{
if (!(num7 < 120f))
{
break;
}
num7 *= 2f;
}
if (num7 > 120f)
{
num7 = 120f;
}
s_nextSentryScan = unscaledTime + num7;
try
{
if (s_sentryType == (Type)null)
{
s_sentryType = Il2CppType.From(typeof(SentryGunInstance));
}
Il2CppReferenceArray<Object> val3 = Object.FindObjectsOfType(s_sentryType);
if (val3 == null)
{
return;
}
for (int k = 0; k < ((Il2CppArrayBase<Object>)(object)val3).Length; k++)
{
SentryGunInstance val4 = ((((Il2CppArrayBase<Object>)(object)val3)[k] != (Object)null) ? ((Il2CppObjectBase)((Il2CppArrayBase<Object>)(object)val3)[k]).TryCast<SentryGunInstance>() : null);
if ((Object)(object)val4 == (Object)null)
{
continue;
}
bool flag3 = false;
for (int l = 0; l < s_scanRefs.Count; l++)
{
if ((Object)(object)s_scanRefs[l] == (Object)(object)val4)
{
flag3 = true;
break;
}
}
if (!flag3)
{
s_scanRefs.Add(val4);
s_scanSlots.Add(-1);
}
}
return;
}
catch
{
return;
}
}
if (!flag2)
{
s_scanMisses = 0;
}
}
internal static void Capture()
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
LoadSentryMemory();
Members.Clear();
InLevel = false;
LastError = null;
try
{
if ((Object)(object)PlayerManager.Current == (Object)null)
{
return;
}
List<PlayerAgent> playerAgentsInLevel = PlayerManager.PlayerAgentsInLevel;
if (playerAgentsInLevel == null)
{
return;
}
InLevel = true;
int localSlot = -1;
try
{
localSlot = PlayerManager.GetLocalPlayerSlotIndex();
}
catch
{
}
for (int i = 0; i < playerAgentsInLevel.Count; i++)
{
MemberView memberView = null;
try
{
PlayerAgent val = playerAgentsInLevel[i];
if ((Object)(object)val != (Object)null)
{
memberView = new MemberView();
ReadMember(val, memberView, localSlot);
}
}
catch (Exception ex)
{
if (memberView == null)
{
memberView = new MemberView();
}
memberView.Error = ex.GetType().Name;
}
if (memberView != null)
{
Members.Add(memberView);
}
}
Members.Sort((MemberView x, MemberView y) => x.SlotIndex.CompareTo(y.SlotIndex));
}
catch (Exception ex2)
{
LastError = ex2.Message;
}
if (!InLevel)
{
s_backpackBySlot.Clear();
s_deployedCheckedAt.Clear();
s_deployedSlots.Clear();
SquadUIArmor.ClearAll();
s_scanRefs.Clear();
s_scanSlots.Clear();
s_scanPlaced.Clear();
s_scanMisses = 0;
}
float realtimeSinceStartup2 = Time.realtimeSinceStartup;
ScanPlacedSentry();
float realtimeSinceStartup3 = Time.realtimeSinceStartup;
Probe();
DumpAmmo();
MsCapture = (realtimeSinceStartup2 - realtimeSinceStartup) * 1000f;
MsScan = (realtimeSinceStartup3 - realtimeSinceStartup2) * 1000f;
if (MsScan > MsScanMax)
{
MsScanMax = MsScan;
}
LastMemberCount = Members.Count;
}
private static void ReadMember(PlayerAgent a, MemberView mv, int localSlot)
{
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
mv.SlotIndex = a.PlayerSlotIndex;
mv.Alive = ((Agent)a).Alive;
try
{
if (SquadUIArmor.TryGet(mv.SlotIndex, out var rel))
{
mv.HasArmor = true;
mv.ArmorRel = Mathf.Clamp01(rel);
}
}
catch
{
}
try
{
mv.Name = a.PlayerName;
}
catch
{
}
if (string.IsNullOrEmpty(mv.Name))
{
mv.Name = "P" + (mv.SlotIndex + 1);
}
try
{
mv.IsLocal = ((localSlot >= 0) ? (mv.SlotIndex == localSlot) : ((Agent)a).IsLocallyOwned);
}
catch
{
mv.IsLocal = false;
}
try
{
mv.Color = PlayerManager.GetStaticPlayerColor(mv.SlotIndex);
}
catch
{
mv.Color = Color.white;
}
Dam_PlayerDamageBase damage = a.Damage;
if ((Object)(object)damage != (Object)null)
{
mv.HasDamage = true;
try
{
mv.Health = ((Dam_SyncedDamageBase)damage).Health;
}
catch
{
}
try
{
mv.HealthMax = ((Dam_SyncedDamageBase)damage).HealthMax;
}
catch
{
}
if (mv.HealthMax <= 0.01f)
{
try
{
mv.HealthMax = ((Dam_SyncedDamageBase)damage).DamageMax;
}
catch
{
}
}
mv.HealthRel = ((mv.HealthMax > 0.01f) ? Mathf.Clamp01(mv.Health / mv.HealthMax) : 0f);
float num = 0f;
try
{
num = damage.Infection;
}
catch
{
}
mv.Infection = Mathf.Clamp01(num);
mv.HasInfection = num > 0.002f;
}
PlayerStamina stamina = a.Stamina;
if ((Object)(object)stamina != (Object)null)
{
mv.HasStamina = true;
try
{
mv.Stamina = stamina.Stamina;
}
catch
{
}
try
{
mv.StaminaMax = PlayerStamina.MaxStamina;
}
catch
{
}
try
{
mv.StaminaRel = stamina.StaminaRelative;
}
catch
{
}
try
{
mv.IsTired = stamina.Tiredness > 0.5f;
}
catch
{
}
if (mv.StaminaRel <= 0f && mv.StaminaMax > 0.01f)
{
mv.StaminaRel = Mathf.Clamp01(mv.Stamina / mv.StaminaMax);
}
if (mv.StaminaMax <= 0.01f && mv.StaminaRel > 0.001f)
{
mv.StaminaMax = mv.Stamina / mv.StaminaRel;
}
mv.StaminaRel = Mathf.Clamp01(mv.StaminaRel);
mv.Bpm = Mathf.Clamp(Mathf.Lerp(68f, 168f, 1f - mv.StaminaRel), 55f, 185f);
}
SNet_Player val = null;
try
{
val = a.Owner;
}
catch
{
}
mv.Player = val;
if (!((Object)(object)val != (Object)null))
{
return;
}
try
{
mv.IsBot = val.IsBot;
}
catch
{
}
PlayerBackpack backpack = GetBackpack(val);
if (backpack != null)
{
PlayerAmmoStorage ammo = null;
try
{
ammo = backpack.AmmoStorage;
}
catch
{
}
ReadAmmo(val, ammo, (InventorySlot)1, (AmmoType)0, mv.Standard, mv.IsLocal, isTool: false, mv.SlotIndex);
ReadAmmo(val, ammo, (InventorySlot)2, (AmmoType)1, mv.Special, mv.IsLocal, isTool: false, mv.SlotIndex);
ReadAmmo(val, ammo, (InventorySlot)3, (AmmoType)2, mv.Tool, mv.IsLocal, isTool: true, mv.SlotIndex);
ReadCarry(val, backpack, ammo, mv);
}
try
{
BackpackItem item = GetItem(val, (InventorySlot)10);
if (item != null && (Object)(object)item.Instance != (Object)null)
{
mv.MeleeName = SafeName(item.Instance);
MeleeWeaponFirstPerson val2 = ((Il2CppObjectBase)item.Instance).TryCast<MeleeWeaponFirstPerson>();
if ((Object)(object)val2 != (Object)null)
{
ReadMeleeState(val2, mv, mv.IsLocal);
}
}
}
catch
{
}
if (!mv.Tool.Present)
{
return;
}
try
{
BackpackItem item2 = GetItem(val, (InventorySlot)3);
ItemEquippable val3 = ((item2 != null && (Object)(object)item2.Instance != (Object)null) ? ((Il2CppObjectBase)item2.Instance).TryCast<ItemEquippable>() : null);
if ((Object)(object)val3 != (Object)null && val3.IsReloading)
{
mv.ToolBusy = true;
mv.ToolBusyLabel = "装填中";
}
}
catch
{
}
}
private static void ReadAmmo(SNet_Player p, PlayerAmmoStorage ammo, InventorySlot slot, AmmoType fallbackType, AmmoView v, bool preferItem, bool isTool, int ownerSlot)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
AmmoType val = fallbackType;
try
{
val = PlayerAmmoStorage.GetAmmoTypeFromSlot(slot);
}
catch
{
}
v.Name = null;
v.Clip = -1;
v.Pack = 0;
v.PackMax = 0;
v.ClipMax = -1;
v.Present = false;
v.Tool = isTool;
v.OwnerSlot = ownerSlot;
int num = -1;
BackpackItem item = GetItem(p, slot);
if (item != null && (Object)(object)item.Instance != (Object)null)
{
v.Present = true;
v.Name = SafeName(item.Instance);
try
{
ItemEquippable val2 = ((Il2CppObjectBase)item.Instance).TryCast<ItemEquippable>();
if ((Object)(object)val2 != (Object)null)
{
num = val2.GetCurrentClip();
v.ClipMax = val2.GetMaxClip();
}
}
catch
{
}
}
int num2 = -1;
if (ammo != null)
{
try
{
num2 = Mathf.Max(0, Mathf.RoundToInt(ammo.GetClipAmmoFromSlot(slot)));
}
catch
{
}
}
v.Clip = ((!preferItem) ? ((num2 >= 0) ? num2 : num) : ((num >= 0) ? num : num2));
if (ammo == null)
{
return;
}
InventorySlotAmmo val3 = null;
try
{
val3 = ammo.GetInventorySlotAmmo(val);
}
catch
{
}
if (isTool)
{
v.Clip = -1;
v.ClipMax = 0;
ItemEquippable val4 = null;
try
{
val4 = ((item != null && (Object)(object)item.Instance != (Object)null) ? ((Il2CppObjectBase)item.Instance).TryCast<ItemEquippable>() : null);
}
catch
{
}
string text = null;
try
{
text = ((item != null && (Object)(object)item.Instance != (Object)null) ? SafeName(item.Instance) : null);
}
catch
{
}
EnemyScanner val5 = ((item != null && (Object)(object)item.Instance != (Object)null) ? ((Il2CppObjectBase)item.Instance).TryCast<EnemyScanner>() : null);
if ((Object)(object)val5 != (Object)null)
{
v.Present = true;
v.NoAmmo = true;
if (!string.IsNullOrEmpty(text) && s_scannerModels.Add(text))
{
SaveSentryMemory();
}
bool flag = preferItem;
if (!flag)
{
try
{
flag = Plugin.Settings?.RemoteScannerPhase.Value ?? false;
}
catch
{
}
}
if (flag)
{
ReadScanner(val5, v);
return;
}
v.PhaseText = "—";
v.PhaseRel = 0f;
return;
}
if (!string.IsNullOrEmpty(text) && s_scannerModels.Contains(text))
{
v.Present = true;
v.NoAmmo = true;
v.PhaseText = "—";
v.PhaseRel = -1f;
return;
}
try
{
PlayerBackpack value = null;
if (v.OwnerSlot >= 0 && !s_backpackBySlot.TryGetValue(v.OwnerSlot, out value))
{
try
{
value = PlayerBackpackManager.GetBackpack(p);
}
catch
{
}
if (value != null)
{
s_backpackBySlot[v.OwnerSlot] = value;
}
}
if (value != null && v.OwnerSlot >= 0)
{
if (!s_deployedCheckedAt.TryGetValue(v.OwnerSlot, out var value2))
{
value2 = -999f;
}
float unscaledTime = Time.unscaledTime;
if (unscaledTime - value2 > 0.2f)
{
s_deployedCheckedAt[v.OwnerSlot] = unscaledTime;
try
{
if (value.IsDeployed((InventorySlot)3))
{
s_deployedSlots[v.OwnerSlot] = text ?? "";
}
}
catch
{
}
}
}
}
catch
{
}
PlacedSentry value3;
bool flag2 = s_scanPlaced.TryGetValue(v.OwnerSlot, out value3);
if (!flag2 && !string.IsNullOrEmpty(text))
{
flag2 = s_scanByModel.TryGetValue(text, out value3);
}
if (flag2)
{
v.Present = true;
v.Tool = true;
v.PhaseRel = ((value3.Max > 0 && value3.Cur >= 0) ? Mathf.Clamp01((float)value3.Cur / (float)value3.Max) : (-1f));
v.Pack = value3.Cur;
v.PackMax = value3.Max;
v.PhaseText = "炮台 " + ((value3.Cur >= 0) ? value3.Cur.ToString() : "--") + ((value3.Max > 0) ? ("/" + value3.Max) : "");
return;
}
if (!string.IsNullOrEmpty(text) && s_sentryModels.Contains(text))
{
float num3 = -1f;
float num4 = -1f;
try
{
if (val3 != null)
{
num3 = val3.AmmoInPack;
num4 = val3.AmmoMaxCap;
}
}
catch
{
}
if (s_sentryCostByName.TryGetValue(text, out var value4) && value4 > 0.0001f && num3 >= 0f)
{
int num5 = Mathf.Max(0, Mathf.FloorToInt(num3 / value4));
int num6 = ((num4 >= 0f) ? Mathf.Max(num5, Mathf.FloorToInt(num4 / value4)) : (-1));
v.Present = true;
v.Tool = true;
v.PhaseRel = ((num6 > 0) ? Mathf.Clamp01((float)num5 / (float)num6) : (-1f));
v.Pack = num5;
v.PackMax = num6;
v.PhaseText = "炮台 " + num5 + ((num6 > 0) ? ("/" + num6) : "");
return;
}
}
SentryGunFirstPerson val6 = null;
try
{
val6 = ((item != null && (Object)(object)item.Instance != (Object)null) ? ((Il2CppObjectBase)item.Instance).TryCast<SentryGunFirstPerson>() : null);
}
catch
{
}
if ((Object)(object)val6 != (Object)null)
{
int num7 = -1;
try
{
num7 = ((ItemEquippable)val6).GetCurrentClip();
}
catch
{
}
int num8 = -1;
if (!string.IsNullOrEmpty(text))
{
float num9 = -1f;
try
{
if (val3 != null)
{
num9 = val3.AmmoMaxCap;
}
}
catch
{
}
if (s_sentryCostByName.TryGetValue(text, out var value5) && value5 > 0.0001f && num9 > 0f)
{
num8 = Mathf.FloorToInt(num9 / value5);
}
}
if (num7 >= 0)
{
v.Present = true;
v.Tool = true;
v.PhaseRel = ((num8 > 0) ? Mathf.Clamp01((float)num7 / (float)num8) : (-1f));
v.Pack = num7;
v.PackMax = num8;
v.PhaseText = "炮台 " + num7 + ((num8 > 0) ? ("/" + num8) : "");
return;
}
}
bool flag3 = false;
float num10 = -1f;
try
{
ArchetypeDataBlock val7 = (((Object)(object)val4 != (Object)null) ? val4.ArchetypeData : null);
if (val7 != null && val7.CostOfBullet > 0.0001f)
{
num10 = val7.CostOfBullet;
}
}
catch
{
}
if (flag3)
{
float num11 = -1f;
float num12 = -1f;
try
{
SentryGunInstance val8 = ((Il2CppObjectBase)item.Instance).TryCast<SentryGunInstance>();
if ((Object)(object)val8 != (Object)null)
{
num11 = val8.Ammo;
num12 = val8.AmmoMaxCap;
}
}
catch
{
}
if (num11 < 0f && val3 != null)
{
num11 = val3.AmmoInPack;
num12 = val3.AmmoMaxCap;
}
float num13 = -1f;
try
{
SentryGunInstance val9 = ((Il2CppObjectBase)item.Instance).TryCast<SentryGunInstance>();
if ((Object)(object)val9 != (Object)null && val9.CostOfBullet > 0.0001f)
{
num13 = val9.CostOfBullet;
}
}
catch
{
}
if (num13 <= 0.0001f)
{
try
{
string text2 = SafeName(item.Instance);
if (!string.IsNullOrEmpty(text2) && s_sentryCostByName.TryGetValue(text2, out var value6) && value6 > 0.0001f)
{
num13 = value6;
}
}
catch
{
}
}
if (num13 <= 0.0001f && (Object)(object)val4 != (Object)null)
{
try
{
ArchetypeDataBlock archetypeData = val4.ArchetypeData;
if (archetypeData != null)
{
float sentryCostOfBullet = archetypeData.GetSentryCostOfBullet(false);
if (sentryCostOfBullet > 0.0001f)
{
num13 = sentryCostOfBullet;
}
}
}
catch
{
}
}
if (num13 <= 0.0001f)
{
num13 = num10;
}
if (num13 <= 0.0001f)
{
num13 = 1f;
}
v.Present = true;
v.PhaseRel = -1f;
int num14 = Mathf.Max(0, Mathf.FloorToInt(((num11 < 0f) ? 0f : num11) / num13));
int packMax = Mathf.Max(num14, Mathf.FloorToInt(((num12 < 0f) ? 0f : num12) / num13));
v.Pack = num14;
v.PackMax = packMax;
v.PhaseText = "炮台 " + num14 + "/" + packMax;
return;
}
int num15 = -1;
int packMax2 = -1;
try
{
ItemEquippable val10 = ((item != null && (Object)(object)item.Instance != (Object)null) ? ((Il2CppObjectBase)item.Instance).TryCast<ItemEquippable>() : null);
if ((Object)(object)val10 != (Object)null && (Object)(object)p != (Object)null)
{
num15 = val10.GetClassAmmoInPackAbs(p);
packMax2 = val10.GetClassAmmoMaxCap(p);
}
}
catch
{
}
if (num15 >= 0)
{
v.Pack = num15;
v.PackMax = packMax2;
}
else if (val3 != null)
{
if (val3.BulletsMaxCap > 0)
{
v.Pack = val3.BulletsInPack;
v.PackMax = val3.BulletsMaxCap;
}
else
{
v.Pack = Mathf.RoundToInt(val3.AmmoInPack);
v.PackMax = Mathf.RoundToInt(val3.AmmoMaxCap);
}
}
if (!v.Present && val3 != null)
{
v.Present = val3.AmmoMaxCap > 0f || val3.BulletsMaxCap > 0;
}
return;
}
try
{
if (val3 != null)
{
if (val3.BulletsMaxCap > 0)
{
v.Pack = val3.BulletsInPack;
v.PackMax = val3.BulletsMaxCap;
}
else
{
v.Pack = Mathf.RoundToInt(val3.AmmoInPack);
v.PackMax = Mathf.RoundToInt(val3.AmmoMaxCap);
}
if (v.ClipMax < 0)
{
v.ClipMax = val3.BulletClipSize;
}
try
{
v.RelPercent = val3.RelInPack;
}
catch
{
}
v.Present |= val3.BulletClipSize > 0 || v.PackMax > 0 || val3.AmmoInPack > 0f;
}
}
catch
{
}
}
private static void ReadScanner(EnemyScanner sc, AmmoView v)
{
bool flag = false;
bool flag2 = false;
try
{
flag = sc.m_tagging;
}
catch
{
}
try
{
flag2 = sc.m_recharging;
}
catch
{
}
float time = Time.time;
float num = 0f;
try
{
num = EnemyScanner.TagDuration;
}
catch
{
}
float num2 = 0f;
try
{
num2 = sc.m_tagStartTime;
}
catch
{
}
float num3 = 0f;
try
{
num3 = sc.m_rechargeDuration;
}
catch
{
}
float num4 = 0f;
try
{
num4 = sc.m_rechargeStartTime;
}
catch
{
}
if (flag)
{
float num5 = time - num2;
if (num <= 0.01f || num5 <= num + 0.75f)
{
if (num > 0.01f)
{
v.PhaseRel = Mathf.Clamp01(num5 / num);
v.PhaseText = "准备 " + Mathf.RoundToInt(v.PhaseRel * 100f) + "%";
}
else
{
v.PhaseRel = -1f;
v.PhaseText = "准备";
}
return;
}
}
float num6 = num3 - (time - num4);
if (flag2 && num3 > 0.01f && num6 > 0f)
{
v.PhaseRel = Mathf.Clamp01(1f - num6 / num3);
v.PhaseWarn = true;
int num7 = Mathf.RoundToInt(num6 * 10f);
v.PhaseText = "冷却 " + num7 / 10 + "." + num7 % 10 + "s";
}
else
{
v.PhaseRel = 1f;
v.PhaseReady = true;
v.PhaseText = "就绪";
}
}
private static string F(float v)
{
return v.ToString("0.###", CultureInfo.InvariantCulture);
}
private static string DumpSlot(SNet_Player p, PlayerAmmoStorage ammo, InventorySlot slot)
{
//IL_0010: 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_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: 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_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
StringBuilder stringBuilder = new StringBuilder();
if (ammo == null)
{
return "no-ammo";
}
AmmoType val = (AmmoType)4;
try
{
val = PlayerAmmoStorage.GetAmmoTypeFromSlot(slot);
}
catch
{
}
stringBuilder.Append("type=").Append(val);
try
{
InventorySlotAmmo inventorySlotAmmo = ammo.GetInventorySlotAmmo(val);
if (inventorySlotAmmo == null)
{
stringBuilder.Append(" isa=-");
}
else
{
stringBuilder.Append(" pack=").Append(F(inventorySlotAmmo.AmmoInPack)).Append(" cap=")
.Append(F(inventorySlotAmmo.AmmoMaxCap))
.Append(" blt=")
.Append(inventorySlotAmmo.BulletsInPack)
.Append(" bltCap=")
.Append(inventorySlotAmmo.BulletsMaxCap)
.Append(" clipSize=")
.Append(inventorySlotAmmo.BulletClipSize)
.Append(" cost=")
.Append(F(inventorySlotAmmo.CostOfBullet))
.Append(" conv=")
.Append(F(inventorySlotAmmo.BulletsToRelConv))
.Append(" rel=")
.Append(F(inventorySlotAmmo.RelInPack))
.Append(" full=")
.Append(inventorySlotAmmo.IsFull);
}
}
catch (Exception ex)
{
stringBuilder.Append(" isaERR=").Append(ex.GetType().Name);
}
try
{
stringBuilder.Append(" clipAbs=").Append(F(ammo.GetClipAmmoFromSlot(slot)));
}
catch
{
}
try
{
stringBuilder.Append(" getPack=").Append(F(ammo.GetAmmoInPack(val)));
}
catch
{
}
try
{
stringBuilder.Append(" getBlt=").Append(ammo.GetBulletsInPack(val)).Append('/')
.Append(ammo.GetBulletMaxCap(val));
}
catch
{
}
BackpackItem item = GetItem(p, slot);
Item val2 = ((item != null) ? item.Instance : null);
if ((Object)(object)val2 == (Object)null)
{
stringBuilder.Append(" item=-");
return stringBuilder.ToString();
}
stringBuilder.Append(" item=").Append(SafeName(val2));
try
{
stringBuilder.Append("(").Append(((object)val2).GetType().Name).Append(")");
}
catch
{
}
try
{
SentryGunInstance val3 = ((Il2CppObjectBase)val2).TryCast<SentryGunInstance>();
if ((Object)(object)val3 != (Object)null)
{
stringBuilder.Append(" SENTRY ammo=").Append(F(val3.Ammo)).Append('/')
.Append(F(val3.AmmoMaxCap))
.Append(" cost=")
.Append(F(val3.CostOfBullet))
.Append(" rounds=")
.Append(F((val3.CostOfBullet > 0.0001f) ? (val3.Ammo / val3.CostOfBullet) : val3.Ammo))
.Append('/')
.Append(F((val3.CostOfBullet > 0.0001f) ? (val3.AmmoMaxCap / val3.CostOfBullet) : val3.AmmoMaxCap))
.Append(" clip=")
.Append(((ItemEquippable)val3).GetCurrentClip())
.Append(" clipRel=")
.Append(F(((ItemEquippable)val3).GetCurrentClipRel()))
.Append(" firing=")
.Append(val3.m_isFiring);
}
}
catch
{
}
try
{
ItemEquippable val4 = ((Il2CppObjectBase)val2).TryCast<ItemEquippable>();
if ((Object)(object)val4 != (Object)null)
{
try
{
ArchetypeDataBlock archetypeData = val4.ArchetypeData;
if (archetypeData != null)
{
stringBuilder.Append(" ARCH cost=").Append(F(archetypeData.CostOfBullet)).Append(" clip=")
.Append(archetypeData.DefaultClipSize)
.Append(" sRange=")
.Append(F(archetypeData.Sentry_DetectionMaxRange))
.Append(" sAngle=")
.Append(F(archetypeData.Sentry_DetectionMaxAngle));
try
{
stringBuilder.Append(" sentryCost(false)=").Append(F(archetypeData.GetSentryCostOfBullet(false)));
}
catch
{
}
try
{
stringBuilder.Append(" sentryCost(true)=").Append(F(archetypeData.GetSentryCostOfBullet(true)));
}
catch
{
}
}
string text = SafeName(val2);
if (!string.IsNullOrEmpty(text) && s_sentryCostByName.TryGetValue(text, out var value))
{
stringBuilder.Append(" CACHE_NAME=").Append(F(value));
}
try
{
ItemEquippable val5 = ((Il2CppObjectBase)val2).TryCast<ItemEquippable>();
if ((Object)(object)val5 != (Object)null && val5.ArchetypeData != null)
{
stringBuilder.Append(" ARCHKEY_HAND=[").Append(ArchKey(val5.ArchetypeData)).Append(']');
}
}
catch
{
}
}
catch
{
}
stringBuilder.Append(" itemClip=").Append(val4.GetCurrentClip()).Append('/')
.Append(val4.GetMaxClip());
try
{
stringBuilder.Append(" classAbs=").Append(val4.GetClassAmmoInPackAbs(p)).Append('/')
.Append(val4.GetClassAmmoMaxCap(p));
}
catch
{
}
}
}
catch
{
}
try
{
EnemyScanner val6 = ((Il2CppObjectBase)val2).TryCast<EnemyScanner>();
if ((Object)(object)val6 != (Object)null)
{
stringBuilder.Append(" SCANNER tag=").Append(val6.m_tagging).Append(" rech=")
.Append(val6.m_recharging)
.Append(" tagStart=")
.Append(F(val6.m_tagStartTime))
.Append(" lock=")
.Append(F(val6.m_lockTimer))
.Append(" scanTimer=")
.Append(F(val6.m_scanTimer))
.Append(" scanDelay=")
.Append(F(val6.m_scanDelay))
.Append(" rechStart=")
.Append(F(val6.m_rechargeStartTime))
.Append(" rechDur=")
.Append(F(val6.m_rechargeDuration))
.Append(" TagDur=")
.Append(F(EnemyScanner.TagDuration));
}
else
{
stringBuilder.Append(" CASTS[");
try
{
if ((Object)(object)((Il2CppObjectBase)val2).TryCast<EnemyScanner>() != (Object)null)
{
stringBuilder.Append("EnemyScanner ");
}
}
catch
{
}
try
{
if ((Object)(object)((Il2CppObjectBase)val2).TryCast<SentryGunFirstPerson>() != (Object)null)
{
stringBuilder.Append("SentryGunFirstPerson ");
}
}
catch
{
}
try
{
if ((Object)(object)((Il2CppObjectBase)val2).TryCast<SentryGunInstance>() != (Object)null)
{
stringBuilder.Append("SentryGunInstance ");
}
}
catch
{
}
try
{
if ((Object)(object)((Il2CppObjectBase)val2).TryCast<MineDeployerInstance>() != (Object)null)
{
stringBuilder.Append("MineDeployerInstance ");
}
}
catch
{
}
try
{
if ((Object)(object)((Il2CppObjectBase)val2).TryCast<ItemEquippable>() != (Object)null)
{
stringBuilder.Append("ItemEquippable ");
}
}
catch
{
}
stringBuilder.Append(']');
}
}
catch
{
}
return stringBuilder.ToString();
}
private static void DumpAmmo()
{
try
{
HudSettings settings = Plugin.Settings;
if (settings == null || !settings.AmmoDump.Value)
{
return;
}
float unscaledTime = Time.unscaledTime;
if (unscaledTime - s_lastDump < 1f)
{
return;
}
s_lastDump = unscaledTime;
for (int i = 0; i < Members.Count; i++)
{
MemberView memberView = Members[i];
SNet_Player player = memberView.Player;
if ((Object)(object)player == (Object)null)
{
Plugin.LogSource.LogInfo((object)("[ammo] " + memberView.Name + " no SNet_Player"));
continue;
}
PlayerBackpack backpack = GetBackpack(player);
PlayerAmmoStorage ammo = ((backpack != null) ? backpack.AmmoStorage : null);
string text = "";
try
{
text = ((backpack == null) ? " DEPLOYED[bp=null]" : (" DEPLOYED[isDeployed=" + backpack.IsDeployed((InventorySlot)3) + "]"));
}
catch (Exception ex)
{
text = " DEPLOYED[err:" + ex.GetType().Name + "]";
}
Plugin.LogSource.LogInfo((object)("[ammo] t=" + F(Time.time) + " " + memberView.Name + " slot=" + memberView.SlotIndex + (memberView.IsLocal ? " LOCAL" : "") + text + " || STD " + DumpSlot(player, ammo, (InventorySlot)1) + " || SPC " + DumpSlot(player, ammo, (InventorySlot)2) + " || TOL " + DumpSlot(player, ammo, (InventorySlot)3)));
}
}
catch (Exception ex2)
{
Plugin.LogSource.LogWarning((object)("[ammo] dump failed: " + ex2.Message));
}
}
private static void ReadCarry(SNet_Player p, PlayerBackpack bp, PlayerAmmoStorage ammo, MemberView mv)
{
mv.Carry.Clear();
AddCarry(p, ammo, (InventorySlot)4, (AmmoType)3, mv);
AddCarry(p, ammo, (InventorySlot)5, (AmmoType)5, mv);
AddCarry(p, ammo, (InventorySlot)6, (AmmoType)5, mv);
mv.Pocket.Clear();
try
{
List<List<PocketItem>> pocketItemsGroups = bp.PocketItemsGroups;
if (pocketItemsGroups == null)
{
return;
}
for (int i = 0; i < pocketItemsGroups.Count; i++)
{
List<PocketItem> val = pocketItemsGroups[i];
if (val != null && val.Count != 0)
{
uint id = 0u;
try
{
id = val[0].itemID;
}
catch
{
}
mv.Pocket.Add(new GearView
{
Name = ItemName(id),
Amount = val.Count
});
}
}
}
catch
{
}
}
private static void AddCarry(SNet_Player p, PlayerAmmoStorage ammo, InventorySlot slot, AmmoType type, MemberView mv)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
BackpackItem item = GetItem(p, slot);
if (item == null || (Object)(object)item.Instance == (Object)null)
{
return;
}
Item instance = item.Instance;
GearView gearView = new GearView();
gearView.Name = SafeName(instance);
try
{
ResourcePackFirstPerson val = ((Il2CppObjectBase)instance).TryCast<ResourcePackFirstPerson>();
if ((Object)(object)val != (Object)null)
{
gearView.IsResourcePack = true;
gearView.Name = PackKindName(val.m_packType);
}
}
catch
{
}
if (ammo != null)
{
try
{
InventorySlotAmmo inventorySlotAmmo = ammo.GetInventorySlotAmmo(type);
if (inventorySlotAmmo != null)
{
gearView.Amount = ((inventorySlotAmmo.BulletsInPack > 0) ? inventorySlotAmmo.BulletsInPack : Mathf.RoundToInt(inventorySlotAmmo.AmmoInPack));
gearView.AmountMax = ((inventorySlotAmmo.BulletsMaxCap > 0) ? inventorySlotAmmo.BulletsMaxCap : Mathf.RoundToInt(inventorySlotAmmo.AmmoMaxCap));
}
}
catch
{
}
}
mv.Carry.Add(gearView);
}
private unsafe static void ReadMeleeState(MeleeWeaponFirstPerson mwf, MemberView mv, bool local)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: 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)
eMeleeWeaponState currentStateName;
try
{
currentStateName = mwf.CurrentStateName;
}
catch
{
return;
}
mv.MeleeState = ((object)(*(eMeleeWeaponState*)(¤tStateName))/*cast due to .constrained prefix*/).ToString();
mv.MeleeCharging = IsChargeState(currentStateName);
try
{
MWS_Base currentState = mwf.CurrentState;
MWS_ChargeUp val = ((currentState != null) ? ((Il2CppObjectBase)currentState).TryCast<MWS_ChargeUp>() : null);
if (val == null)
{
mv.MeleeChargeRel = 0f;
return;
}
float maxDamageTime = val.m_maxDamageTime;
float elapsed = val.m_elapsed;
float num = ((!(maxDamageTime > 0.01f)) ? val.m_animTimeRel : (elapsed / maxDamageTime));
mv.MeleeChargeRel = Mathf.Clamp01(num);
mv.MeleeChargeElapsed = elapsed;
float value;
if (maxDamageTime > 0.01f)
{
s_lastMeleeNeed[mv.SlotIndex] = maxDamageTime;
mv.MeleeChargeSeconds = maxDamageTime;
mv.MeleeChargeNeed = maxDamageTime;
}
else if (s_lastMeleeNeed.TryGetValue(mv.SlotIndex, out value))
{
mv.MeleeChargeNeed = value;
}
}
catch
{
mv.MeleeChargeRel = 0f;
}
}
private static bool IsChargeState(eMeleeWeaponState s)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Invalid comparison between Unknown and I4
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Invalid comparison between Unknown and I4
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Invalid comparison between Unknown and I4
if ((int)s != 7 && (int)s != 9 && (int)s != 8 && (int)s != 10 && (int)s != 11)
{
return (int)s == 12;
}
return true;
}
private static PlayerBackpack GetBackpack(SNet_Player p)
{
if ((Object)(object)p == (Object)null)
{
return null;
}
try
{
PlayerBackpack backpack = PlayerBackpackManager.GetBackpack(p);
if (backpack != null)
{
return backpack;
}
}
catch
{
}
try
{
return PlayerBackpackManager.GetLocalOrSyncBackpack(p);
}
catch
{
return null;
}
}
private static BackpackItem GetItem(SNet_Player p, InventorySlot slot)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)p == (Object)null)
{
return null;
}
try
{
return PlayerBackpackManager.GetItem(p, slot);
}
catch
{
return null;
}
}
private static string SafeName(Item inst)
{
if ((Object)(object)inst == (Object)null)
{
return null;
}
try
{
string publicName = inst.PublicName;
if (!string.IsNullOrEmpty(publicName))
{
return publicName;
}
}
catch
{
}
try
{
string archetypeName = inst.ArchetypeName;
if (!string.IsNullOrEmpty(archetypeName))
{
return archetypeName;
}
}
catch
{
}
try
{
ItemDataBlock itemDataBlock = inst.ItemDataBlock;
if (itemDataBlock != null)
{
string name = itemDataBlock.GetName();
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
}
catch
{
}
return null;
}
private unsafe static string PackKindName(eResourceContainerSpawnType t)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected I4, but got Unknown
return (int)t switch
{
0 => "医疗包",
1 => "弹药包",
2 => "工具包",
9 => "消毒包",
6 => "消耗品",
3 => "物资(小)",
4 => "物资(中)",
5 => "物资(大)",
7 => "钥匙卡",
10 => "神器",
_ => ((object)(*(eResourceContainerSpawnType*)(&t))/*cast due to .constrained prefix*/).ToString(),
};
}
private static string ItemName(uint id)
{
try
{
HudSettings settings = Plugin.Settings;
if (settings != null && !settings.ShowPocket.Value)
{
return "#" + id;
}
if (s_itemNameCache.TryGetValue(id, out var value))
{
return value;
}
string text = null;
try
{
Dictionary<uint, ItemDataBlock> s_blockByID = GameDataBlockBase<ItemDataBlock>.s_blockByID;
ItemDataBlock val = default(ItemDataBlock);
if (s_blockByID != null && s_blockByID.TryGetValue(id, ref val) && val != null)
{
try
{
text = val.publicName;
}
catch
{
}
if (string.IsNullOrEmpty(text))
{
try
{
text = val.GetName();
}
catch
{
}
}
}
}
catch
{
}
if (!string.IsNullOrEmpty(text))
{
s_itemNameCache[id] = text;
return text;
}
return "#" + id;
}
catch
{
return "#" + id;
}
}
private static void Probe()
{
try
{
HudSettings settings = Plugin.Settings;
if (settings == null || !settings.ProbeLog.Value)
{
return;
}
float unscaledTime = Time.unscaledTime;
if (unscaledTime - s_lastProbe < 1f)
{
return;
}
s_lastProbe = unscaledTime;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("[probe] inLevel=").Append(InLevel).Append(" members=")
.Append(Members.Count);
for (int i = 0; i < Members.Count; i++)
{
MemberView memberView = Members[i];
stringBuilder.Append(" | ").Append(memberView.Name).Append(" slot=")
.Append(memberView.SlotIndex)
.Append(memberView.IsLocal ? " local" : "")
.Append(" hp=")
.Append(Mathf.RoundToInt(memberView.Health))
.Append("/")
.Append(Mathf.RoundToInt(memberView.HealthMax))
.Append(" inf=")
.Append(Mathf.RoundToInt(memberView.Infection * 100f));
if (memberView.HasStamina)
{
stringBuilder.Append(" sta=").Append(Mathf.RoundToInt(memberView.StaminaRel * 100f));
}
stringBuilder.Append(" std=").Append(memberView.Standard.Clip).Append("/")
.Append(memberView.Standard.Pack)
.Append("/")
.Append(memberView.Standard.PackMax)
.Append(" spc=")
.Append(memberView.Special.Clip)
.Append("/")
.Append(memberView.Special.Pack)
.Append("/")
.Append(memberView.Special.PackMax)
.Append(" tol=")
.Append(memberView.Tool.Clip)
.Append("/")
.Append(memberView.Tool.Pack)
.Append("/")
.Append(memberView.Tool.PackMax)
.Append(" melee=")
.Append(memberView.MeleeName ?? "-")
.Append(" carry=")
.Append(memberView.Carry.Count)
.Append(" pocket=")
.Append(memberView.Pocket.Count);
if (memberView.Error != null)
{
stringBuilder.Append(" ERR=").Append(memberView.Error);
}
}
if (LastError != null)
{
stringBuilder.Append(" ROOTERR=").Append(LastError);
}
Plugin.LogSource.LogInfo((object)stringBuilder.ToString());
}
catch
{
}
}
}
}