using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using Agents; using BepInEx; using Enemies; using GameData; using Gear; using Hikaria.Core; using Hikaria.Core.SNetworkExt; using Hikaria.DamageAnalyzer.Features; using Hikaria.DamageAnalyzer.Handlers; using Hikaria.DamageAnalyzer.Managers; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Collections.Generic; using Player; using SNetwork; using TMPro; using TheArchive.Core; using TheArchive.Core.Attributes; using TheArchive.Core.Attributes.Feature; using TheArchive.Core.Attributes.Feature.Members; using TheArchive.Core.Attributes.Feature.Patches; using TheArchive.Core.Attributes.Feature.Settings; using TheArchive.Core.FeaturesAPI; using TheArchive.Core.Localization; using TheArchive.Core.Models; using TheArchive.Core.ModulesAPI; using TheArchive.Interfaces; using TheArchive.Loader; using TheArchive.Utilities; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace Hikaria.DamageAnalyzer { internal static class DebugTypeScanner { private static readonly string[] Keywords = new string[12] { "Damage", "Dam_", "EnemyDamage", "EnemyDamageLimb", "BulletWeapon", "BulletHit", "MeleeDamage", "BulletDamage", "SentryGunInstance", "PUI_Watermark", "GuiManager", "Watermark" }; private static bool _hasScanned; public static void Scan() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0079: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown if (_hasScanned) { return; } _hasScanned = true; try { string text = Path.Combine(Paths.BepInExRootPath, "interop"); string text2 = Path.Combine(Paths.BepInExRootPath, "core"); if (!Directory.Exists(text)) { Logs.LogWarning("DebugTypeScanner skipped: interop folder not found at " + text + "."); return; } Logs.LogInfo("DebugTypeScanner scanning " + text + "."); DefaultAssemblyResolver val = new DefaultAssemblyResolver(); ((BaseAssemblyResolver)val).AddSearchDirectory(text); ((BaseAssemblyResolver)val).AddSearchDirectory(text2); ReaderParameters readerParameters = new ReaderParameters { AssemblyResolver = (IAssemblyResolver)(object)val, InMemory = true }; foreach (string item in Directory.EnumerateFiles(text, "*.dll")) { ScanAssembly(item, readerParameters); } } catch (Exception value) { Logs.LogError($"DebugTypeScanner failed: {value}"); } } private static void ScanAssembly(string assemblyPath, ReaderParameters readerParameters) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) AssemblyDefinition val; try { val = AssemblyDefinition.ReadAssembly(assemblyPath, readerParameters); } catch (Exception ex) { Logs.LogWarning("DebugTypeScanner could not read " + Path.GetFileName(assemblyPath) + ": " + ex.Message); return; } AssemblyDefinition val2 = val; try { Enumerator enumerator = val.Modules.GetEnumerator(); try { while (enumerator.MoveNext()) { foreach (TypeDefinition item in EnumerateTypes((IEnumerable)enumerator.Current.Types)) { bool num = ContainsKeyword(((MemberReference)item).FullName); MethodDefinition[] array = ((IEnumerable)item.Methods).Where((MethodDefinition method) => ContainsKeyword(((MemberReference)method).Name)).ToArray(); if (num || array.Length != 0) { Logs.LogInfo($"DebugTypeScanner type {((MemberReference)item).FullName} [{Path.GetFileName(assemblyPath)}]"); MethodDefinition[] array2 = array; foreach (MethodDefinition val3 in array2) { Logs.LogInfo($"DebugTypeScanner method {((MemberReference)item).FullName}.{((MemberReference)val3).Name}({FormatParameters(val3)}) -> {((MemberReference)((MethodReference)val3).ReturnType).FullName}"); } } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } finally { ((IDisposable)val2)?.Dispose(); } } private static IEnumerable EnumerateTypes(IEnumerable types) { foreach (TypeDefinition type in types) { yield return type; foreach (TypeDefinition item in EnumerateTypes((IEnumerable)type.NestedTypes)) { yield return item; } } } private static bool ContainsKeyword(string value) { return Keywords.Any((string keyword) => value.Contains(keyword, StringComparison.OrdinalIgnoreCase)); } private static string FormatParameters(MethodDefinition method) { return string.Join(", ", ((IEnumerable)((MethodReference)method).Parameters).Select((ParameterDefinition parameter) => ((MemberReference)((ParameterReference)parameter).ParameterType).FullName + " " + ((ParameterReference)parameter).Name)); } } [ArchiveDependency(/*Could not decode attribute arguments.*/)] [ArchiveModule("Hikaria.DamageAnalyzer", "DamageAnalyzer", "2.0.0")] public class EntryPoint : IArchiveModule { public ILocalizationService LocalizationService { get; set; } public IArchiveLogger Logger { get; set; } public void Init() { Logs.Setup(Logger); } } internal static class Logs { private const string Prefix = "[DamageAnalyzer.Restore]"; private static IArchiveLogger _logger; public static void Setup(IArchiveLogger logger) { _logger = logger; } public static void LogDebug(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Debug(Format(data)); } } public static void LogError(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Error(Format(data)); } } public static void LogInfo(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Info(Format(data)); } } public static void LogMessage(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Msg(ConsoleColor.White, Format(data)); } } public static void LogWarning(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Warning(Format(data)); } } public static void LogNotice(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Notice(Format(data)); } } public static void LogSuccess(object data) { IArchiveLogger logger = _logger; if (logger != null) { logger.Success(Format(data)); } } public static void LogException(Exception ex) { _logger.Exception(ex); } private static string Format(object data) { return $"{"[DamageAnalyzer.Restore]"} {data}"; } } public static class PluginInfo { public const string GUID = "Hikaria.DamageAnalyzer"; public const string NAME = "DamageAnalyzer"; public const string VERSION = "2.0.0"; } } namespace Hikaria.DamageAnalyzer.Managers { public static class DamageInfoManager { public struct pDamageInfo { public pPlayer player; public BasicDamageInfo damageInfo; public pDamageInfo(SNet_Player player, BasicDamageInfo damageInfo) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) this.player = default(pPlayer); ((pPlayer)(ref this.player)).SetPlayer(player); this.damageInfo = damageInfo; } } public struct BasicDamageInfo { public pPlayer player; public pEnemyAgent enemy; public float rawDamage; public int limbID; public bool allowDirectionalBonus; public bool isSleepMulti; public float staggerMulti; public float precisionMulti; public float backstabberMulti; public float sleeperMulti; public DamageType damageType; public DamageSource damageSource; public Vector3 position; public Vector3 direction; public BasicDamageInfo(SNet_Player player, DamageType damageType, DamageSource damageSource, Dam_EnemyDamageLimb limb, Vector3 position, Vector3 direction, float rawDamage, bool allowDirectionalBonus = false, float staggerMulti = 1f, float precisionMulti = 1f, float backstabberMulti = 1f, float sleeperMulti = 1f, bool isSleepMulti = false) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) this.player = default(pPlayer); ((pPlayer)(ref this.player)).SetPlayer(player); this.damageType = damageType; this.damageSource = damageSource; enemy = default(pEnemyAgent); ((pEnemyAgent)(ref enemy)).Set(limb.m_base.Owner); limbID = limb.m_limbID; this.position = position; this.direction = direction; this.rawDamage = rawDamage; this.allowDirectionalBonus = allowDirectionalBonus; this.staggerMulti = staggerMulti; this.precisionMulti = precisionMulti; this.backstabberMulti = backstabberMulti; this.sleeperMulti = sleeperMulti; this.isSleepMulti = isSleepMulti; } } public enum DamageType : byte { Bullet, Melee } public enum DamageSource : byte { SentryGun, Player } public static bool ShowSentryDamage = true; public static uint LocalAgentGlobalID; public static bool IsSleepMulti; public static bool IsSentryGunFire; public static Dictionary OriginalBulletDamage = new Dictionary(); private static SNetExt_AuthorativeAction m_packet; public static void Setup() { //IL_000a: 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_0019: 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) VersionRange compatibleVersions = new VersionRange(new Version(2, 0, 0), new Version(3, 0, 0), true, false); m_packet = SNetExt_AuthorativeAction.Create(typeof(pDamageInfo).FullName, (Action)ReceiveDamageInfo, (Action)null, (Func)((SNet_Player p) => CoreAPI.IsPlayerInstalledMod(p, "Hikaria.DamageAnalyzer", compatibleVersions)), (SNet_ChannelType)4); } public static void SendDamageInfo(BasicDamageInfo damageInfo, SNet_Player player) { m_packet.Ask(new pDamageInfo(player, damageInfo)); } private static void ReceiveDamageInfo(SNet_Player sender, pDamageInfo data) { SNet_Player val = default(SNet_Player); if (((pPlayer)(ref data.player)).TryGetPlayer(ref val) && val.IsLocal && (Object)(object)sender != (Object)null && sender.IsMaster) { OriginalBulletDamage[val.Lookup] = data.damageInfo.rawDamage; ProcessDamageInfo(data.damageInfo); } } public static void ProcessDamageInfo(BasicDamageInfo damageInfo) { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Invalid comparison between Unknown and I4 //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Invalid comparison between Unknown and I4 //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DamageInfoUpdater.Instance == (Object)null) { Logs.LogWarning("ProcessDamageInfo skipped: DamageInfoUpdater.Instance is null."); return; } SNet_Player player = default(SNet_Player); EnemyAgent val = default(EnemyAgent); if (!((pPlayer)(ref damageInfo.player)).TryGetPlayer(ref player) || !((pEnemyAgent)(ref damageInfo.enemy)).TryGet(ref val)) { Logs.LogWarning("ProcessDamageInfo skipped: player or enemy lookup failed."); return; } if ((Object)(object)val.Damage == (Object)null || val.Damage.DamageLimbs == null || damageInfo.limbID < 0 || damageInfo.limbID >= ((Il2CppArrayBase)(object)val.Damage.DamageLimbs).Length) { Logs.LogWarning($"ProcessDamageInfo skipped: invalid limb index {damageInfo.limbID}."); return; } Dam_EnemyDamageLimb val2 = ((Il2CppArrayBase)(object)val.Damage.DamageLimbs)[damageInfo.limbID]; if ((Object)(object)val2 == (Object)null) { Logs.LogWarning($"ProcessDamageInfo skipped: limb {damageInfo.limbID} is null."); return; } float num = damageInfo.rawDamage; bool isCrit = false; bool isArmor = false; bool isBackMulti = false; bool isSleepMulti = damageInfo.isSleepMulti; bool isImortal = val.Damage.IsImortal; bool allowDirectionalBonus = damageInfo.allowDirectionalBonus; float precisionMulti = damageInfo.precisionMulti; float sleeperMulti = damageInfo.sleeperMulti; float backstabberMulti = damageInfo.backstabberMulti; Vector3 direction = damageInfo.direction; Vector3 position = damageInfo.position; DamageType damageType = damageInfo.damageType; DamageSource damageSource = damageInfo.damageSource; if ((Object)(object)val2 != (Object)null) { if ((int)val2.m_type == 1) { isCrit = true; } else if ((int)val2.m_type == 2) { isArmor = true; } } switch (damageType) { case DamageType.Bullet: { if (!OriginalBulletDamage.TryGetValue(player.Lookup, out var value)) { Logs.LogWarning($"ProcessDamageInfo skipped: OriginalBulletDamage missing for player {player.Lookup}."); return; } if (damageSource == DamageSource.SentryGun) { if (!player.IsLocal) { if (SNet.IsMaster && ((SNetExt_SyncedAction)(object)m_packet).Listeners.Any((SNet_Player p) => p.Lookup == player.Lookup)) { SendDamageInfo(damageInfo, player); } return; } if (player.IsLocal && !ShowSentryDamage) { return; } } num = AgentModifierManager.ApplyModifier((Agent)(object)val, (AgentModifier)7, value); break; } case DamageType.Melee: num = AgentModifierManager.ApplyModifier((Agent)(object)val, (AgentModifier)6, num); if (isSleepMulti) { num *= sleeperMulti; } break; } num = val2.ApplyWeakspotAndArmorModifiers(num, precisionMulti); if (allowDirectionalBonus) { float num2 = num; num = val2.ApplyDamageFromBehindBonus(num, position, direction, backstabberMulti); if (num > num2) { isBackMulti = true; } } if (Hikaria.DamageAnalyzer.Features.DamageAnalyzer.EnableVerboseRestoreLog) { Logs.LogInfo($"Damage hook triggered: type={damageType}, source={damageSource}, raw={damageInfo.rawDamage:0.00}, real={num:0.00}, limb={damageInfo.limbID}."); } DamageInfoUpdater.Instance.UpdateBasicDamageInfo(val2, isImortal, isArmor, isCrit, isBackMulti, IsSleepMulti, num); } } internal static class TranslateManager { public struct EnemyIDName { public List IDs; public string Name; } private struct EnemyLimbName { public string Contain; public string Name; } private static CustomSetting> EnemyIDNameSettings = new CustomSetting>("EnemyIDNames", new List(), (Action>)delegate(List data) { EnemyID2NameLookup = new Dictionary(); foreach (EnemyIDName datum in data) { foreach (uint iD in datum.IDs) { EnemyID2NameLookup[iD] = datum.Name; } } }, (LoadingTime)1, true); private static CustomSetting> EnemyLimbNameSettings = new CustomSetting>("EnemyLimbNames", new List(), (Action>)delegate(List data) { EnemyLimbNamesLookup = data.ToDictionary((EnemyLimbName x) => x.Contain.ToLower(), (EnemyLimbName x) => x.Name); }, (LoadingTime)1, true); private static Dictionary EnemyLimbNamesLookup; private static Dictionary EnemyID2NameLookup; public static string KILL => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(1u, (string)null); public static string IMMORTAL => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(2u, (string)null); public static string UNKNOWN => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(3u, (string)null); public static string ARMOR => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(4u, (string)null); public static string CRIT => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(5u, (string)null); public static string BACKMULTI => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(6u, (string)null); public static string SLEEPMULTI => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(7u, (string)null); public static string HITPOSITION_DESC => Hikaria.DamageAnalyzer.Features.DamageAnalyzer.Localization.GetById(8u, (string)null); public static string EnemyName(uint id) { if (!EnemyID2NameLookup.TryGetValue(id, out var value)) { return $"{((GameDataBlockBase)(object)GameDataBlockBase.GetBlock(id)).name} [{id}]"; } return value; } public static string EnemyLimb(string LimbName) { LimbName = LimbName.ToLower(); if (EnemyLimbNamesLookup.Any(delegate(KeyValuePair x) { if (LimbName.Contains(x.Key)) { LimbName = x.Value; return true; } return false; })) { return LimbName; } return UNKNOWN; } } } namespace Hikaria.DamageAnalyzer.Handlers { public class DamageInfoUpdater : MonoBehaviour { private bool Status; private float timer; private static StringBuilder sb = new StringBuilder(500); private Dam_EnemyDamageBase _dmgBase; private float _healthMax; private float _health; private bool _isImmortal; private string _limbName = string.Empty; private string _enemyName = string.Empty; private bool _isKill; private bool _isArmor; private bool _isCrit; private bool _isBackMulti; private bool _isSleepMulti; private float _damage; public static float LastingTime = 2.5f; public static int BarFontSize = 12; public static int HintFontSize = 12; public static int BarLength = 80; public static int OffsetX = 970; public static int OffsetY = 790; public static bool ShowHints = true; public static string BarFillChar_Remaining = "#"; public static string BarFillChar_Lost = "-"; public static bool ShowHPBar = true; public static bool ShowName = true; public static bool ShowLimb = true; public static bool ShowDamage = true; public static Color TextColor = new Color(1f, 1f, 0.8823f, 0.7059f); public static TextMeshPro TextMesh; public static DamageInfoUpdater Instance { get; private set; } public static TextMeshPro WatermarkTextPrefab => GuiManager.WatermarkLayer.m_watermark.m_watermarkText; private void Awake() { //IL_0049: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Instance = this; TextMesh = Object.Instantiate(WatermarkTextPrefab); ((Transform)((TMP_Text)TextMesh).rectTransform).SetParent(((Transform)((TMP_Text)WatermarkTextPrefab).rectTransform).parent); ((Transform)((TMP_Text)TextMesh).rectTransform).localPosition = new Vector3((float)OffsetX, (float)OffsetY); ((TMP_Text)TextMesh).rectTransform.sizeDelta = new Vector2(1920f, ((TMP_Text)TextMesh).rectTransform.sizeDelta.y); ((Graphic)TextMesh).color = TextColor; ((TMP_Text)TextMesh).alignment = (TextAlignmentOptions)257; ((TMP_Text)TextMesh).SetText(string.Empty, true); ((Transform)((TMP_Text)TextMesh).rectTransform).localScale = Vector3.zero; } private void FixedUpdate() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (timer >= LastingTime) { ((Transform)((TMP_Text)TextMesh).rectTransform).localScale = Vector3.zero; Status = false; } if (Status) { timer += Time.fixedDeltaTime; UpdateDamageInfo(); } } private void RestartTimer() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) timer = 0f; Status = true; ((Transform)((TMP_Text)TextMesh).rectTransform).localScale = Vector3.one; } public void UpdateBasicDamageInfo(Dam_EnemyDamageLimb dam_EnemyDamageLimb, bool isImmortal, bool isArmor, bool isCrit, bool isBackMulti, bool isSleepMulti, float damage) { _dmgBase = dam_EnemyDamageLimb.m_base; _limbName = TranslateManager.EnemyLimb(((Object)dam_EnemyDamageLimb).name); _enemyName = TranslateManager.EnemyName(_dmgBase.Owner.EnemyDataID); _isImmortal = isImmortal; _isArmor = isArmor; _isCrit = isCrit; _isBackMulti = isBackMulti; _isSleepMulti = isSleepMulti; _damage = (isImmortal ? 0f : damage); RestartTimer(); } private void UpdateDamageInfo() { bool flag = (Object)(object)_dmgBase != (Object)null; if (flag) { _health = ((Dam_SyncedDamageBase)_dmgBase).Health; _healthMax = ((Dam_SyncedDamageBase)_dmgBase).HealthMax; } else { _health = 0f; } _health = Math.Max(_health, 0f); _health = (float)Math.Round(_health, 1); if (flag) { _isKill = !flag || ((Dam_SyncedDamageBase)_dmgBase).Health <= 0f; } else { _isKill = true; } StringBuilder stringBuilder = sb; StringBuilder stringBuilder2 = stringBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder); handler.AppendLiteral(""); stringBuilder2.Append(ref handler); if (ShowName) { sb.Append(_enemyName); } if (ShowLimb) { if (ShowName) { stringBuilder = sb; StringBuilder stringBuilder3 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder); handler.AppendLiteral(" ("); handler.AppendFormatted(_limbName); handler.AppendLiteral(")"); stringBuilder3.Append(ref handler); } else { stringBuilder = sb; StringBuilder stringBuilder4 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(2, 2, stringBuilder); handler.AppendFormatted(TranslateManager.HITPOSITION_DESC); handler.AppendLiteral(": "); handler.AppendFormatted(_limbName); stringBuilder4.Append(ref handler); } } sb.Append("\n"); if (ShowHPBar) { stringBuilder = sb; StringBuilder stringBuilder5 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(13, 1, stringBuilder); handler.AppendLiteral("HP: |-"); stringBuilder5.Append(ref handler); int num = (int)(_health / _healthMax * (float)BarLength); if (num == 0 && !_isKill) { num = 1; } sb.Append(BarFillChar_Remaining[0], num); sb.Append(BarFillChar_Lost[0], BarLength - num); sb.Append("-| "); } else { stringBuilder = sb; StringBuilder stringBuilder6 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(18, 1, stringBuilder); handler.AppendLiteral("HP: "); stringBuilder6.Append(ref handler); } stringBuilder = sb; StringBuilder stringBuilder7 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(19, 3, stringBuilder); handler.AppendLiteral("["); handler.AppendFormatted(_health); handler.AppendLiteral(" / "); handler.AppendFormatted(_healthMax); handler.AppendLiteral("]"); stringBuilder7.AppendLine(ref handler); if (ShowHints) { stringBuilder = sb; StringBuilder stringBuilder8 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder); handler.AppendLiteral(""); stringBuilder8.Append(ref handler); if (ShowDamage) { stringBuilder = sb; StringBuilder stringBuilder9 = stringBuilder; handler = new StringBuilder.AppendInterpolatedStringHandler(4, 1, stringBuilder); handler.AppendLiteral("HP -"); handler.AppendFormatted(_damage.ToString("0.00")); stringBuilder9.AppendLine(ref handler); } if (_isCrit) { sb.AppendLine(TranslateManager.CRIT); } if (_isBackMulti) { sb.AppendLine(TranslateManager.BACKMULTI); } if (_isSleepMulti) { sb.AppendLine(TranslateManager.SLEEPMULTI); } if (_isImmortal) { sb.AppendLine(TranslateManager.IMMORTAL); } if (_isArmor) { sb.AppendLine(TranslateManager.ARMOR); } if (_isKill) { sb.AppendLine(TranslateManager.KILL); } sb.Append(""); } ((TMP_Text)TextMesh).SetText(sb.ToString(), true); sb.Clear(); } } } namespace Hikaria.DamageAnalyzer.Features { [DisallowInGameToggle] [EnableFeatureByDefault] public class DamageAnalyzer : Feature { public class DamageAnalyzerSetting { [FSDisplayName("持续时间")] public float LastingTime { get { return DamageInfoUpdater.LastingTime; } set { DamageInfoUpdater.LastingTime = value; } } [FSDisplayName("生命值条文本大小")] public int BarFontSize { get { return DamageInfoUpdater.BarFontSize; } set { DamageInfoUpdater.BarFontSize = value; } } [FSDisplayName("提示文本大小")] public int HintFontSize { get { return DamageInfoUpdater.HintFontSize; } set { DamageInfoUpdater.HintFontSize = value; } } [FSDisplayName("生命值条文本长度")] public int BarLength { get { return DamageInfoUpdater.BarLength; } set { DamageInfoUpdater.BarLength = value; } } [FSDisplayName("显示位置横向偏移量")] public int OffsetX { get { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DamageInfoUpdater.TextMesh == (Object)null) { return DamageInfoUpdater.OffsetX; } return (int)DamageInfoUpdater.TextMesh.transform.localPosition.x; } set { //IL_002c: Unknown result type (might be due to invalid IL or missing references) DamageInfoUpdater.OffsetX = value; if (!((Object)(object)DamageInfoUpdater.TextMesh == (Object)null)) { DamageInfoUpdater.TextMesh.transform.localPosition = new Vector3((float)value, (float)OffsetY, 0f); } } } [FSDisplayName("显示位置纵向偏移量")] public int OffsetY { get { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)DamageInfoUpdater.TextMesh == (Object)null) { return DamageInfoUpdater.OffsetY; } return (int)DamageInfoUpdater.TextMesh.transform.localPosition.y; } set { //IL_002c: Unknown result type (might be due to invalid IL or missing references) DamageInfoUpdater.OffsetY = value; if (!((Object)(object)DamageInfoUpdater.TextMesh == (Object)null)) { DamageInfoUpdater.TextMesh.transform.localPosition = new Vector3((float)OffsetX, (float)value, 0f); } } } [FSDisplayName("显示提示")] public bool ShowHints { get { return DamageInfoUpdater.ShowHints; } set { DamageInfoUpdater.ShowHints = value; } } [FSDisplayName("显示生命值条")] public bool ShowHPBar { get { return DamageInfoUpdater.ShowHPBar; } set { DamageInfoUpdater.ShowHPBar = value; } } [FSDisplayName("显示敌人名称")] public bool ShowName { get { return DamageInfoUpdater.ShowName; } set { DamageInfoUpdater.ShowName = value; } } [FSDisplayName("显示命中部位")] public bool ShowLimb { get { return DamageInfoUpdater.ShowLimb; } set { DamageInfoUpdater.ShowLimb = value; } } [FSDisplayName("显示造成的伤害")] public bool ShowDamage { get { return DamageInfoUpdater.ShowDamage; } set { DamageInfoUpdater.ShowDamage = value; } } [FSDisplayName("显示哨戒炮造成的伤害")] [FSDescription("显示哨戒炮的命中信息, 仅当房主也安装了本插件才能显示")] public bool ShowSentryDamage { get { return DamageInfoManager.ShowSentryDamage; } set { DamageInfoManager.ShowSentryDamage = value; } } [FSDisplayName("Enable verbose restore log")] public bool EnableVerboseRestoreLog { get { return DamageAnalyzer.EnableVerboseRestoreLog; } set { DamageAnalyzer.EnableVerboseRestoreLog = value; } } [FSDisplayName("Enable debug scanner")] public bool EnableDebugScanner { get { return DamageAnalyzer.EnableDebugScanner; } set { DamageAnalyzer.EnableDebugScanner = value; } } [FSDisplayName("生命值剩余表示字符")] public string BarFillChar_Remaining { get { return DamageInfoUpdater.BarFillChar_Remaining; } set { DamageInfoUpdater.BarFillChar_Remaining = value; } } [FSDisplayName("生命值失去表示字符")] public string BarFillChar_Lost { get { return DamageInfoUpdater.BarFillChar_Lost; } set { DamageInfoUpdater.BarFillChar_Lost = value; } } [FSDisplayName("文本颜色")] public SColor TextColor { get { //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_000d: 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) if ((Object)(object)DamageInfoUpdater.TextMesh == (Object)null) { return SColorExtensions.ToSColor(DamageInfoUpdater.TextColor); } return SColorExtensions.ToSColor(((Graphic)DamageInfoUpdater.TextMesh).color); } set { //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_0006: 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_001f: Unknown result type (might be due to invalid IL or missing references) DamageInfoUpdater.TextColor = SColorExtensions.ToUnityColor(value); if (!((Object)(object)DamageInfoUpdater.TextMesh == (Object)null)) { ((Graphic)DamageInfoUpdater.TextMesh).color = SColorExtensions.ToUnityColor(value); } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class PUI_Watermark__UpdateWatermark__Patch { private static bool IsSetup; private static void Postfix() { //IL_000c: 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_002f: 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_003f: Expected O, but got Unknown if (!IsSetup) { GameObject val = new GameObject("DamageAnalyzer"); val.transform.position = new Vector3((float)Screen.width / 2f, (float)Screen.height / 2f); Object.DontDestroyOnLoad((Object)val); val.AddComponent(); IsSetup = true; } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class BulletWeapon__BulletHit__Patch { private static void Prefix(WeaponHitData weaponRayData, bool doDamage, float additionalDis) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if (EnableVerboseRestoreLog) { Logs.LogInfo("ENTER BulletWeapon.BulletHit"); } SNet_Player owner = weaponRayData.owner.Owner; if (!DamageInfoManager.OriginalBulletDamage.TryAdd(owner.Lookup, weaponRayData.damage)) { DamageInfoManager.OriginalBulletDamage[owner.Lookup] = weaponRayData.damage; } RaycastHit rayHit = weaponRayData.rayHit; float num = ((RaycastHit)(ref rayHit)).distance + additionalDis; if (num > weaponRayData.damageFalloff.x) { DamageInfoManager.OriginalBulletDamage[owner.Lookup] *= Mathf.Max(1f - (num - weaponRayData.damageFalloff.x) / (weaponRayData.damageFalloff.y - weaponRayData.damageFalloff.x), BulletWeapon.s_falloffMin); } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageLimb__MeleeDamage__Patch { private static void Prefix(Dam_EnemyDamageLimb __instance, float dam, Agent sourceAgent, Vector3 position, Vector3 direction, float staggerMulti = 1f, float precisionMulti = 1f, float backstabberMulti = 1f, float sleeperMulti = 1f) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Invalid comparison between Unknown and I4 if (EnableVerboseRestoreLog) { Logs.LogInfo($"ENTER Dam_EnemyDamageLimb.MeleeDamage Prefix sourceAgent={(Object)(object)sourceAgent != (Object)null} local={DamageInfoManager.LocalAgentGlobalID} source={((sourceAgent != null) ? new ushort?(sourceAgent.GlobalID) : ((ushort?)null))}"); } if (!((Object)(object)sourceAgent == (Object)null) && DamageInfoManager.LocalAgentGlobalID == sourceAgent.GlobalID && !((Il2CppObjectBase)sourceAgent).TryCast().Owner.IsBot && (int)__instance.m_base.Owner.Locomotion.CurrentStateEnum == 14) { DamageInfoManager.IsSleepMulti = true; } } private static void Postfix(Dam_EnemyDamageLimb __instance, float dam, Agent sourceAgent, Vector3 position, Vector3 direction, float staggerMulti = 1f, float precisionMulti = 1f, float backstabberMulti = 1f, float sleeperMulti = 1f) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if (EnableVerboseRestoreLog) { Logs.LogInfo($"ENTER Dam_EnemyDamageLimb.MeleeDamage Postfix sourceAgent={(Object)(object)sourceAgent != (Object)null} local={DamageInfoManager.LocalAgentGlobalID} source={((sourceAgent != null) ? new ushort?(sourceAgent.GlobalID) : ((ushort?)null))}"); } if (!((Object)(object)sourceAgent == (Object)null) && DamageInfoManager.LocalAgentGlobalID == sourceAgent.GlobalID) { PlayerAgent val = ((Il2CppObjectBase)sourceAgent).TryCast(); if (!val.Owner.IsBot) { DamageInfoManager.ProcessDamageInfo(new DamageInfoManager.BasicDamageInfo(val.Owner, DamageInfoManager.DamageType.Melee, DamageInfoManager.DamageSource.Player, __instance, position, direction, dam, allowDirectionalBonus: true, staggerMulti, precisionMulti, backstabberMulti, sleeperMulti, DamageInfoManager.IsSleepMulti)); DamageInfoManager.IsSleepMulti = false; } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class Dam_EnemyDamageLimb__BulletDamage__Patch { private static void Postfix(Dam_EnemyDamageLimb __instance, float dam, Agent sourceAgent, Vector3 position, Vector3 direction, bool allowDirectionalBonus, float staggerMulti = 1f, float precisionMulti = 1f) { //IL_00c1: 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) if (EnableVerboseRestoreLog) { Logs.LogInfo($"ENTER Dam_EnemyDamageLimb.BulletDamage sourceAgent={(Object)(object)sourceAgent != (Object)null} local={DamageInfoManager.LocalAgentGlobalID} source={((sourceAgent != null) ? new ushort?(sourceAgent.GlobalID) : ((ushort?)null))}"); } if (!((Object)(object)sourceAgent == (Object)null) && (SNet.IsMaster || DamageInfoManager.LocalAgentGlobalID == sourceAgent.GlobalID)) { PlayerAgent val = ((Il2CppObjectBase)sourceAgent).TryCast(); if (!val.Owner.IsBot) { DamageInfoManager.ProcessDamageInfo(new DamageInfoManager.BasicDamageInfo(val.Owner, DamageInfoManager.DamageType.Bullet, (!DamageInfoManager.IsSentryGunFire) ? DamageInfoManager.DamageSource.Player : DamageInfoManager.DamageSource.SentryGun, __instance, position, direction, dam, allowDirectionalBonus, staggerMulti, precisionMulti)); } } } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SentryGunInstance_Firing_Bullets__FireBullet__Patch { private static void Prefix() { DamageInfoManager.IsSentryGunFire = true; } private static void Postfix() { DamageInfoManager.IsSentryGunFire = false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class SentryGunInstance_Firing_Bullets__UpdateFireShotgunSemi__Patch { private static void Prefix(SentryGunInstance_Firing_Bullets __instance) { if (Clock.Time > __instance.m_fireBulletTimer) { DamageInfoManager.IsSentryGunFire = true; } } private static void Postfix() { DamageInfoManager.IsSentryGunFire = false; } } [ArchivePatch(/*Could not decode attribute arguments.*/)] private class LocalPlayerAgent__Setup__Patch { private static void Postfix(LocalPlayerAgent __instance) { Logs.LogInfo($"LocalPlayerAgent.Setup localGlobalID={((Agent)__instance).GlobalID}"); DamageInfoManager.LocalAgentGlobalID = ((Agent)__instance).GlobalID; } } public static bool EnableVerboseRestoreLog; public static bool EnableDebugScanner; public override string Name => "Damage Analyzer"; public override bool InlineSettingsIntoParentMenu => true; public static ILocalizationService Localization { get; set; } [FeatureConfig] public static DamageAnalyzerSetting Settings { get; set; } public override void Init() { Logs.LogInfo("DamageAnalyzer loaded"); Logs.LogInfo(EnableDebugScanner ? "DebugTypeScanner enabled" : "DebugTypeScanner disabled"); if (EnableDebugScanner) { DebugTypeScanner.Scan(); } ClassInjector.RegisterTypeInIl2Cpp(false); DamageInfoManager.Setup(); } } }