using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using BepInEx; using BepInEx.Configuration; using BepInEx.Unity.IL2CPP; using CellMenu; using GameData; using Gear; using HarmonyLib; using Localization; using Microsoft.CodeAnalysis; using Player; using UnityEngine; using WeaponStatShower.Patches; using WeaponStatShower.Utils; using WeaponStatShower.Utils.Language; using WeaponStatShower.Utils.Language.Models; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("WeaponStatShower")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+85c316c320eef37590a4119a82a5ae81c084d884")] [assembly: AssemblyProduct("WeaponStatShower")] [assembly: AssemblyTitle("WeaponStatShower")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace WeaponStatShower { public static class BIEExtensions { public static ConfigEntry GetConfigEntry(this ConfigFile configFile, ConfigDefinition definition) { ConfigEntry result = default(ConfigEntry); if (!configFile.TryGetEntry(definition, ref result)) { throw new InvalidOperationException("Config entry has not been added yet."); } return result; } } [BepInPlugin("WeaponStatShower", "Weapon Stat Shower", "1.5.2")] [BepInProcess("GTFO.exe")] public class WeaponStatShowerPlugin : BasePlugin { internal const string ModName = "Weapon Stat Shower"; internal const string GUID = "WeaponStatShower"; private const string SectionMain = "Config"; private static readonly ConfigDefinition ConfigDefinition = new ConfigDefinition("Config", "Version"); private static readonly ConfigDefinition ConfigGameVersion = new ConfigDefinition("Config", "GameVersion"); private static Harmony? HarmonyInstance; private static readonly Dictionary RegisteredPatches = new Dictionary(); public static WeaponStatShowerPlugin Instance { get; private set; } public WeaponStatShowerPlugin() { ((BasePlugin)this).Config.SaveOnConfigSet = false; } public override void Load() { Instance = this; ((BasePlugin)this).Config.SaveOnConfigSet = true; LogInfo("STARTED"); RegisterPatch(); ((BasePlugin)this).Config.Save(); } public static void RegisterPatch() where T : Patch, new() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if (HarmonyInstance == null) { HarmonyInstance = new Harmony("WeaponStatShower"); } if (RegisteredPatches.TryGetValue(typeof(T), out Patch _)) { LogDebug("Ignoring duplicate patch: " + typeof(T).Name); return; } T val = new T { Harmony = HarmonyInstance }; val.Initialize(); if (val.Enabled) { LogInfo("Applying patch: " + val.Name); val.Execute(); } RegisteredPatches[typeof(T)] = val; } public static void LogDebug(object data) { ((BasePlugin)Instance).Log.LogDebug(data); } public static void LogError(object data) { ((BasePlugin)Instance).Log.LogError(data); } public static void LogFatal(object data) { ((BasePlugin)Instance).Log.LogFatal(data); } public static void LogInfo(object data) { ((BasePlugin)Instance).Log.LogInfo(data); } public static void LogMessage(object data) { ((BasePlugin)Instance).Log.LogMessage(data); } public static void LogWarning(object data) { ((BasePlugin)Instance).Log.LogWarning(data); } } } namespace WeaponStatShower.Utils { internal static class ArchetypeUtil { internal static ArchetypeDataBlock? GetArchetypeDataBlock(GearIDRange idRange, uint categoryID, GearCategoryDataBlock gearCatBlock) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) eWeaponFireMode val = (eWeaponFireMode)idRange.GetCompID((eGearComponent)1); return (categoryID == 12) ? SentryGunInstance_Firing_Bullets.GetArchetypeDataForFireMode(val) : GameDataBlockBase.GetBlock(GearBuilder.GetArchetypeID(gearCatBlock, val)); } internal static ArchetypeDataBlock? GetMappedArchetypeDataBlock(GearIDRange idRange, uint categoryID, GearCategoryDataBlock gearCatBlock) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected I4, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0044: Unknown result type (might be due to invalid IL or missing references) eWeaponFireMode val = (eWeaponFireMode)idRange.GetCompID((eGearComponent)1); bool flag = categoryID == 12; if (!flag) { val = (eWeaponFireMode)((val - 10) switch { 0 => 0, 1 => 2, 2 => 1, 3 => 0, _ => val, }); } return flag ? SentryGunInstance_Firing_Bullets.GetArchetypeDataForFireMode(val) : GameDataBlockBase.GetBlock(GearBuilder.GetArchetypeID(gearCatBlock, val)); } } internal class SleepersDatas { private readonly struct EnemyData { public readonly float Health; public readonly float HeadMultiplier; public readonly float BackMultiplier; public readonly bool IsArmored; public EnemyData(float health, float headMultiplier, float backMultiplier, bool isArmored) { Health = health; HeadMultiplier = headMultiplier; BackMultiplier = backMultiplier; IsArmored = isArmored; } } private readonly Dictionary _enemyDatas = new Dictionary(); private readonly SleepersLanguageModel sleepersLanguageDatas; public SleepersDatas(string[] activatedSleepers, SleepersLanguageModel sleepersLanguageDatas) { this.sleepersLanguageDatas = sleepersLanguageDatas; foreach (string text in activatedSleepers) { string text2 = text.Trim(); switch (text2) { case "DETAILS_ONLY": case "DESCRIPTION_ONLY": case "NONE": _enemyDatas.Clear(); return; case "ALL": _enemyDatas.Clear(); _enemyDatas.TryAdd(sleepersLanguageDatas.striker, new EnemyData(20f, 3f, 2f, isArmored: false)); _enemyDatas.TryAdd(sleepersLanguageDatas.shooter, new EnemyData(30f, 5f, 2f, isArmored: false)); _enemyDatas.TryAdd(sleepersLanguageDatas.scout, new EnemyData(42f, 3f, 2f, isArmored: false)); _enemyDatas.TryAdd(sleepersLanguageDatas.bigStriker, new EnemyData(120f, 1.5f, 2f, isArmored: false)); _enemyDatas.TryAdd(sleepersLanguageDatas.bigShooter, new EnemyData(150f, 2f, 2f, isArmored: false)); _enemyDatas.TryAdd(sleepersLanguageDatas.charger, new EnemyData(30f, 1f, 2f, isArmored: true)); _enemyDatas.TryAdd(sleepersLanguageDatas.chargerScout, new EnemyData(60f, 1f, 2f, isArmored: true)); return; case "STRIKER": _enemyDatas.TryAdd(sleepersLanguageDatas.striker, new EnemyData(20f, 3f, 2f, isArmored: false)); break; case "SHOOTER": _enemyDatas.TryAdd(sleepersLanguageDatas.shooter, new EnemyData(30f, 5f, 2f, isArmored: false)); break; case "SCOUT": _enemyDatas.TryAdd(sleepersLanguageDatas.scout, new EnemyData(42f, 3f, 2f, isArmored: false)); break; case "BIG_STRIKER": _enemyDatas.TryAdd(sleepersLanguageDatas.bigStriker, new EnemyData(120f, 1.5f, 2f, isArmored: false)); break; case "BIG_SHOOTER": _enemyDatas.TryAdd(sleepersLanguageDatas.bigShooter, new EnemyData(150f, 2f, 2f, isArmored: false)); break; case "CHARGER": _enemyDatas.TryAdd(sleepersLanguageDatas.charger, new EnemyData(30f, 1f, 2f, isArmored: true)); break; case "CHARGER_SCOUT": _enemyDatas.TryAdd(sleepersLanguageDatas.chargerScout, new EnemyData(60f, 1f, 2f, isArmored: true)); break; default: WeaponStatShowerPlugin.LogWarning("You inserted an incorrect value in the config: " + text2); break; } } } public string VerboseKill(ArchetypeDataBlock archetypeDB) { float damage = archetypeDB.Damage * (float)((archetypeDB.ShotgunBulletCount <= 0) ? 1 : archetypeDB.ShotgunBulletCount); float precisionDamageMulti = archetypeDB.PrecisionDamageMulti; return BuildKillString(precisionDamageMulti, (string _, EnemyData __) => damage); } internal string? VerboseKill(MeleeArchetypeDataBlock meleeArchetypeDB) { MeleeArchetypeDataBlock meleeArchetypeDB2 = meleeArchetypeDB; float baseDamage = meleeArchetypeDB2.ChargedAttackDamage * meleeArchetypeDB2.ChargedSleeperMulti; float chargedPrecisionMulti = meleeArchetypeDB2.ChargedPrecisionMulti; return BuildKillString(chargedPrecisionMulti, delegate(string enemyName, EnemyData _) { float num = baseDamage; if (enemyName.Contains("SCOUT") || enemyName.Contains("哨兵") || enemyName.Contains("黑触")) { num /= meleeArchetypeDB2.ChargedSleeperMulti; } return num; }); } private string BuildKillString(float prcnMult, Func getDamage) { StringBuilder stringBuilder = new StringBuilder(); int num = 0; int num2 = 0; int num3 = _enemyDatas.Count - 1; foreach (KeyValuePair enemyData2 in _enemyDatas) { enemyData2.Deconstruct(out var key, out var value); string text = key; EnemyData enemyData = value; float damage = getDamage(text, enemyData); List list = new List(4); if (canKillOnOccipit(damage, prcnMult, enemyData)) { list.Add(sleepersLanguageDatas.occipit); } if (canKillOnHead(damage, prcnMult, enemyData)) { list.Add(sleepersLanguageDatas.head); } if (canKillOnBack(damage, enemyData)) { list.Add(sleepersLanguageDatas.back); } if (canKillOnChest(damage, enemyData)) { list.Add(sleepersLanguageDatas.chest); } if (list.Count > 0) { if (num % 2 == 1) { stringBuilder.Append(" | "); } list.Reverse(); stringBuilder.Append(text + ": [" + string.Join(",", list) + "]"); if (num++ % 2 == 1 && num2 != num3) { stringBuilder.AppendLine(); } } num2++; } if (num > 1 && stringBuilder.Length > 0) { if (stringBuilder[stringBuilder.Length - 1] != '\n') { stringBuilder.AppendLine(); } } return stringBuilder.ToString(); } private bool canKillOnChest(float damage, EnemyData data) { return damage >= data.Health; } private bool canKillOnBack(float damage, EnemyData data) { return damage * data.BackMultiplier >= data.Health; } private bool canKillOnHead(float damage, float prcnMultiplier, EnemyData data) { if (isArmored(data)) { return damage * data.HeadMultiplier >= data.Health; } return damage * prcnMultiplier * data.HeadMultiplier >= data.Health; } private bool canKillOnOccipit(float damage, float prcnMultiplier, EnemyData data) { if (isArmored(data)) { return damage * data.BackMultiplier * data.HeadMultiplier >= data.Health; } return damage * prcnMultiplier * data.BackMultiplier * data.HeadMultiplier >= data.Health; } private bool isArmored(EnemyData data) { return data.IsArmored; } } internal class WeaponDescriptionBuilder { private SleepersDatas _sleepersDatas; private PlayerDataBlock _playerDB; private GearIDRange _idRange; private uint _categoryID; private GearCategoryDataBlock _gearCategoryDB; private ItemDataBlock _itemDB; private LanguageDatas _languageDatas; private LanguageEnum _language; private LanguageEnum? _cachedLanguage; private LanguageDatas? _cachedLanguageDatas; private bool _showStats; private bool _showDescription; private readonly StringBuilder _strBuilder = new StringBuilder(); private const string DIVIDER = " | "; private const string CLOSE_COLOR_TAG = ""; internal void Inizialize(GearIDRange idRange, PlayerDataBlock playerDB, LanguageEnum language, bool showStats, bool showDescription) { _idRange = idRange; _playerDB = playerDB; _language = language; _categoryID = idRange.GetCompID((eGearComponent)2); _gearCategoryDB = GameDataBlockBase.GetBlock(_categoryID); _itemDB = GameDataBlockBase.GetBlock(_gearCategoryDB.BaseItem); _languageDatas = DeserializeLanguageJson(language); _showStats = showStats; _showDescription = showDescription; } public void UpdateSleepersDatas(string[] activatedSleepers, LanguageEnum language) { if (activatedSleepers[0].Trim().Length == 0) { WeaponStatShowerPlugin.LogWarning("Empty String in the config file, applying Default values"); activatedSleepers = new string[1] { "ALL" }; } _sleepersDatas = new SleepersDatas(activatedSleepers, DeserializeLanguageJson(language).sleepers); } private LanguageDatas DeserializeLanguageJson(LanguageEnum language) { if (_cachedLanguage == language && _cachedLanguageDatas != null) { return _cachedLanguageDatas; } LanguageDatasClass languageDatasClass = JsonSerializer.Deserialize(LocalizedString.JsonString); _cachedLanguageDatas = (language.Equals(LanguageEnum.English) ? languageDatasClass.english : languageDatasClass.chinese); _cachedLanguage = language; return _cachedLanguageDatas; } public string DescriptionFormatter(string gearDescription) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)_itemDB.inventorySlot == 10) { MeleeArchetypeDataBlock block = GameDataBlockBase.GetBlock(GearBuilder.GetMeleeArchetypeID(_gearCategoryDB)); gearDescription = VerboseDescriptionFormatter(block); return gearDescription + GetFormatedWeaponStats(block, _itemDB); } var (val, isSentry) = GetRangedArchetype(); if (val == null) { return (_showStats || _showDescription) ? string.Empty : gearDescription; } gearDescription = VerboseDescriptionFormatter(val, isSentry); return gearDescription + GetFormatedWeaponStats(val, isSentry); } internal string FireRateFormatter(string gearPublicName) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)_itemDB.inventorySlot == 10) { MeleeArchetypeDataBlock block = GameDataBlockBase.GetBlock(GearBuilder.GetMeleeArchetypeID(_gearCategoryDB)); MeleeLanguageModel melee = _languageDatas.melee; return ((GameDataBlockBase)(object)block).persistentID switch { 1u => melee.hammer, 2u => melee.knife, 3u => melee.spear, 4u => melee.bat, _ => gearPublicName, }; } ArchetypeDataBlock item = GetRangedArchetype().Item1; if (item == null) { return gearPublicName; } return VerbosePublicNameFireMode(item); } private (ArchetypeDataBlock?, bool) GetRangedArchetype() { bool item = _categoryID == 12; return (ArchetypeUtil.GetMappedArchetypeDataBlock(_idRange, _categoryID, _gearCategoryDB), item); } private string VerbosePublicNameFireMode(ArchetypeDataBlock archetypeDB) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected I4, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) FiremodeLanguageModel firemode = _languageDatas.firemode; eWeaponFireMode fireMode = archetypeDB.FireMode; _strBuilder.Clear(); eWeaponFireMode val = fireMode; eWeaponFireMode val2 = val; switch ((int)val2) { case 2: case 11: { StringBuilder strBuilder = _strBuilder; StringBuilder stringBuilder6 = strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 4, strBuilder); handler.AppendFormatted(firemode.fullA); handler.AppendLiteral(" (<#12FF50>"); handler.AppendFormatted(_languageDatas.rateOfFire); handler.AppendLiteral(" "); handler.AppendFormatted(GetRateOfFire(archetypeDB, fireMode)); handler.AppendFormatted(""); handler.AppendLiteral(")"); stringBuilder6.Append(ref handler); break; } case 0: case 10: { StringBuilder strBuilder = _strBuilder; StringBuilder stringBuilder5 = strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 4, strBuilder); handler.AppendFormatted(firemode.semiA); handler.AppendLiteral(" (<#12FF50>"); handler.AppendFormatted(_languageDatas.rateOfFire); handler.AppendLiteral(" "); handler.AppendFormatted(GetRateOfFire(archetypeDB, fireMode)); handler.AppendFormatted(""); handler.AppendLiteral(")"); stringBuilder5.Append(ref handler); break; } case 1: case 12: if (archetypeDB.BurstShotCount != 1) { StringBuilder strBuilder = _strBuilder; StringBuilder stringBuilder3 = strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(23, 7, strBuilder); handler.AppendFormatted(firemode.burst); handler.AppendLiteral(" (<#704dfa>#"); handler.AppendFormatted(archetypeDB.BurstShotCount); handler.AppendFormatted(""); handler.AppendFormatted(" | "); handler.AppendLiteral("<#12FF50>"); handler.AppendFormatted(_languageDatas.rateOfFire); handler.AppendLiteral(" "); handler.AppendFormatted(GetRateOfFire(archetypeDB, fireMode)); handler.AppendFormatted(""); handler.AppendLiteral(")"); stringBuilder3.Append(ref handler); } else { StringBuilder strBuilder = _strBuilder; StringBuilder stringBuilder4 = strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 4, strBuilder); handler.AppendFormatted(firemode.burst); handler.AppendLiteral(" (<#12FF50>"); handler.AppendFormatted(_languageDatas.rateOfFire); handler.AppendLiteral(" "); handler.AppendFormatted(GetRateOfFire(archetypeDB, (eWeaponFireMode)0)); handler.AppendFormatted(""); handler.AppendLiteral(")"); stringBuilder4.Append(ref handler); } break; case 3: { StringBuilder strBuilder = _strBuilder; StringBuilder stringBuilder2 = strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(28, 3, strBuilder); handler.AppendLiteral("S-Burst (<#12FF50>#"); handler.AppendFormatted(archetypeDB.BurstShotCount); handler.AppendLiteral(" every "); handler.AppendFormatted(archetypeDB.SpecialSemiBurstCountTimeout); handler.AppendLiteral("'"); handler.AppendFormatted(""); handler.AppendLiteral(")"); stringBuilder2.Append(ref handler); break; } case 13: { StringBuilder strBuilder = _strBuilder; StringBuilder stringBuilder = strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(13, 4, strBuilder); handler.AppendFormatted(firemode.shotgunSentry); handler.AppendLiteral(" (<#12FF50>"); handler.AppendFormatted(_languageDatas.rateOfFire); handler.AppendLiteral(" "); handler.AppendFormatted(GetRateOfFire(archetypeDB, fireMode)); handler.AppendFormatted(""); handler.AppendLiteral(")"); stringBuilder.Append(ref handler); break; } default: WeaponStatShowerPlugin.LogError("FireMode not found"); break; } return _strBuilder.ToString(); } private string VerboseDescriptionFormatter(ArchetypeDataBlock archetypeDB, bool isSentry) { SpreadLanguageModel spread = _languageDatas.spread; _strBuilder.Clear(); switch (archetypeDB.ShotgunBulletSpread + archetypeDB.ShotgunConeSize) { case 1: _strBuilder.AppendLine(spread.chocked); break; case 4: _strBuilder.AppendLine(spread.small); break; case 5: case 7: _strBuilder.AppendLine(spread.medium); break; case 9: _strBuilder.AppendLine(spread.huge); break; default: WeaponStatShowerPlugin.LogError(LocalizedText.op_Implicit(archetypeDB.PublicName) + ": spread not considered{" + archetypeDB.ShotgunBulletSpread + "/" + archetypeDB.ShotgunConeSize + "}"); break; case 0: break; } float specialChargetupTime = archetypeDB.SpecialChargetupTime; if (specialChargetupTime > 0f) { string value = (((double)specialChargetupTime > 0.4) ? _languageDatas.longChargeUp : _languageDatas.shortChargeUp); StringBuilder strBuilder = _strBuilder; StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(3, 2, strBuilder); handler.AppendFormatted(value); handler.AppendLiteral(" ("); handler.AppendFormatted(FormatFloat(specialChargetupTime, 2)); handler.AppendLiteral(")"); strBuilder.AppendLine(ref handler); } return (_strBuilder.Length == 0) ? string.Empty : (_strBuilder.ToString() + "\n"); } private string VerboseDescriptionFormatter(MeleeArchetypeDataBlock meleeArchetypeDB) { _strBuilder.Clear(); if ((double)meleeArchetypeDB.CameraDamageRayLength < 1.76) { _strBuilder.AppendLine(_languageDatas.melee.shortRange); } else if ((double)meleeArchetypeDB.CameraDamageRayLength < 2.5) { _strBuilder.AppendLine(_languageDatas.melee.mediumRange); } else { _strBuilder.AppendLine(_languageDatas.melee.longRange); } _strBuilder.Append(meleeArchetypeDB.CanHitMultipleEnemies ? (_languageDatas.melee.canPierce + "\n") : string.Empty); return (_strBuilder.Length == 0) ? string.Empty : _strBuilder.ToString(); } private string GetFormatedWeaponStats(ArchetypeDataBlock archetypeDB, bool isSentry = false) { //IL_01fe: Unknown result type (might be due to invalid IL or missing references) if (archetypeDB == null) { return string.Empty; } int count = 0; int dividerThreshold = ((_language != 0) ? 3 : 4); _strBuilder.Clear(); if (_showStats) { string value = FormatFloat(archetypeDB.Damage, 2) + ((archetypeDB.ShotgunBulletCount > 0) ? $"(x{archetypeDB.ShotgunBulletCount})" : ""); AppendStat(ref count, "<#9D2929>", _languageDatas.damage, value); AppendStatIf(ref count, Divider, !isSentry, "", _languageDatas.clip, archetypeDB.DefaultClipSize.ToString()); Divider(); AppendStat(ref count, "<#FFD306>", _languageDatas.maxAmmo, GetTotalAmmo(archetypeDB, _itemDB, isSentry).ToString()); AppendStatIf(ref count, Divider, !isSentry, "<#C0FF00>", _languageDatas.reload, FormatFloat(archetypeDB.DefaultReloadTime, 2).ToString()); AppendStatIf(ref count, Divider, archetypeDB.PrecisionDamageMulti != 1f, "<#18A4A9>", _languageDatas.precision, FormatFloat(archetypeDB.PrecisionDamageMulti, 2).ToString()); Divider(); AppendStat(ref count, "<#6764de>", _languageDatas.falloff, (int)archetypeDB.DamageFalloff.x + "m"); AppendStatIf(ref count, Divider, archetypeDB.StaggerDamageMulti != 1f, "", _languageDatas.stagger, FormatFloat(archetypeDB.StaggerDamageMulti, 2).ToString()); AppendStatIf(ref count, Divider, archetypeDB.HipFireSpread != 0f && archetypeDB.ShotgunBulletCount == 0, "<#cc9347>", _languageDatas.hipSpread, FormatFloat(archetypeDB.HipFireSpread, 2).ToString()); AppendStatIf(ref count, Divider, archetypeDB.AimSpread != 0f && archetypeDB.ShotgunBulletCount == 0, "<#e6583c>", _languageDatas.aimDSpread, FormatFloat(archetypeDB.AimSpread, 2).ToString()); AppendStatIf(ref count, Divider, archetypeDB.PiercingBullets, "<#097345>", _languageDatas.pierceCount, archetypeDB.PiercingDamageCountLimit.ToString()); _strBuilder.AppendLine(); } _strBuilder.Append(_sleepersDatas.VerboseKill(archetypeDB)); return _strBuilder.ToString(); void Divider() { if (count >= dividerThreshold) { _strBuilder.AppendLine(); count = 0; } else if (count > 0) { _strBuilder.Append(" | "); } } } private string GetFormatedWeaponStats(MeleeArchetypeDataBlock meleeArchetypeDB, ItemDataBlock itemDB) { if (meleeArchetypeDB == null) { return string.Empty; } int count = 0; MeleeLanguageModel melee = _languageDatas.melee; _strBuilder.Clear(); if (_showStats) { _strBuilder.AppendLine(); AppendStat(ref count, "<#9D2929>", _languageDatas.damage + "." + melee.light, meleeArchetypeDB.LightAttackDamage.ToString()); Divider(); AppendStat(ref count, "", _languageDatas.damage + "." + melee.heavy, meleeArchetypeDB.ChargedAttackDamage.ToString()); AppendStatIf(ref count, Divider, !meleeArchetypeDB.AllowRunningWhenCharging, "<#FFD306>", melee.canRunWhileCharging); AppendStatIf(ref count, Divider, meleeArchetypeDB.LightStaggerMulti != 1f, "<#C0FF00>", _languageDatas.stagger + "." + melee.light, meleeArchetypeDB.LightStaggerMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.ChargedStaggerMulti != 1f, "", _languageDatas.stagger + "." + melee.heavy, meleeArchetypeDB.ChargedStaggerMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.LightPrecisionMulti != 1f, "<#004E2C>", _languageDatas.precision + "." + melee.light, meleeArchetypeDB.LightPrecisionMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.ChargedPrecisionMulti != 1f, "<#55022B>", _languageDatas.precision + "." + melee.heavy, meleeArchetypeDB.ChargedPrecisionMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.LightSleeperMulti != 1f, "<#A918A7>", melee.sleepingEnemiesMultiplier + "." + melee.light, meleeArchetypeDB.LightSleeperMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.ChargedSleeperMulti != 1f, "<#025531>", melee.sleepingEnemiesMultiplier + "." + melee.heavy, meleeArchetypeDB.ChargedSleeperMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.LightEnvironmentMulti != 1f, "<#18A4A9>", melee.environmentMultiplier + "." + melee.light, meleeArchetypeDB.LightEnvironmentMulti.ToString()); AppendStatIf(ref count, Divider, meleeArchetypeDB.ChargedEnvironmentMulti != 1f, "<#75A2AA>", melee.environmentMultiplier + "." + melee.heavy, meleeArchetypeDB.ChargedEnvironmentMulti.ToString()); _strBuilder.AppendLine(); } _strBuilder.Append(_sleepersDatas.VerboseKill(meleeArchetypeDB) ?? string.Empty); return _strBuilder.ToString(); void Divider() { if (count >= 3) { _strBuilder.AppendLine(); count = 0; } else if (count > 0) { _strBuilder.Append(" | "); } } } private void AppendStatIf(ref int count, Action divider, bool condition, string color, string label, string value = "") { if (condition) { divider(); AppendStat(ref count, color, label, value); } } private void AppendStat(ref int count, string color, string label, string value = "") { _strBuilder.Append(color); _strBuilder.Append(label); if (!string.IsNullOrEmpty(value)) { _strBuilder.Append(' '); _strBuilder.Append(value); } _strBuilder.Append(""); count++; } private static float FormatFloat(float value, int v) { return (float)Math.Round((decimal)value, v); } private int GetAmmoMax(ItemDataBlock itemDataBlock) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_002b: Expected I4, but got Unknown AmmoType ammoTypeFromSlot = PlayerAmmoStorage.GetAmmoTypeFromSlot(itemDataBlock.inventorySlot); return (int)ammoTypeFromSlot switch { 0 => _playerDB.AmmoStandardMaxCap, 1 => _playerDB.AmmoSpecialMaxCap, 2 => _playerDB.AmmoClassMaxCap, 5 => itemDataBlock.ConsumableAmmoMax, _ => -1, }; } private int GetTotalAmmo(ArchetypeDataBlock archetypeDB, ItemDataBlock itemDB, bool isSentry = false) { int ammoMax = GetAmmoMax(itemDB); float num = archetypeDB.CostOfBullet; if (isSentry) { num *= itemDB.ClassAmmoCostFactor; if ((float)archetypeDB.ShotgunBulletCount > 0f) { num *= (float)archetypeDB.ShotgunBulletCount; } } int num2 = (int)((float)ammoMax / num); return isSentry ? num2 : (num2 + archetypeDB.DefaultClipSize); } private string GetRateOfFire(ArchetypeDataBlock archetypeDB, eWeaponFireMode fireMode) { //IL_0007: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_001d: Expected I4, but got Unknown //IL_001f: 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_0034: Expected I4, but got Unknown float value = -1f; float num; switch ((int)fireMode) { default: switch (fireMode - 11) { case 0: break; case 2: goto IL_0045; case 1: goto IL_005b; default: goto end_IL_000c; } goto case 2; case 2: value = 1f / archetypeDB.ShotDelay; break; case 0: goto IL_0045; case 1: goto IL_005b; IL_005b: num = 1f / (archetypeDB.BurstDelay + archetypeDB.SpecialChargetupTime + archetypeDB.ShotDelay * (float)(archetypeDB.BurstShotCount - 1)); value = num * (float)archetypeDB.BurstShotCount; break; IL_0045: value = 1f / (archetypeDB.ShotDelay + archetypeDB.SpecialChargetupTime); break; end_IL_000c: break; } return FormatFloat(value, 1).ToString(); } } } namespace WeaponStatShower.Utils.Language { public class LanguageDatas { public FiremodeLanguageModel firemode { get; set; } = new FiremodeLanguageModel(); public MeleeLanguageModel melee { get; set; } = new MeleeLanguageModel(); public SpreadLanguageModel spread { get; set; } = new SpreadLanguageModel(); public SleepersLanguageModel sleepers { get; set; } = new SleepersLanguageModel(); public string damage { get; set; } = string.Empty; public string clip { get; set; } = string.Empty; public string maxAmmo { get; set; } = string.Empty; public string falloff { get; set; } = string.Empty; public string reload { get; set; } = string.Empty; public string stagger { get; set; } = string.Empty; public string precision { get; set; } = string.Empty; public string pierceCount { get; set; } = string.Empty; public string rateOfFire { get; set; } = string.Empty; public string aimDSpread { get; set; } = string.Empty; public string hipSpread { get; set; } = string.Empty; public string deployable { get; set; } = string.Empty; public string longChargeUp { get; set; } = string.Empty; public string shortChargeUp { get; set; } = string.Empty; } internal class LanguageDatasClass { public LanguageDatas english { get; set; } = new LanguageDatas(); public LanguageDatas chinese { get; set; } = new LanguageDatas(); } internal enum LanguageEnum { English, Chinese } internal class LocalizedString { public static readonly string JsonString = "{\r\n\t\t\t\"english\": {\r\n\t\t\t\t\"firemode\": {\r\n\t\t\t\t\t\"fullA\": \"Full-A\",\r\n\t\t\t\t\t\"semiA\": \"Semi-A\",\r\n\t\t\t\t\t\"burst\": \"Burst\",\r\n\t\t\t\t\t\"shotgunSentry\": \"Shotgun-S\"\r\n\t\t\t\t},\r\n\t\t\t\t\"melee\": {\r\n\t\t\t\t\t\"light\": \"Lgt\",\r\n\t\t\t\t\t\"heavy\": \"Hvy\",\r\n\t\t\t\t\t\"canRunWhileCharging\": \"Can't run\",\r\n\t\t\t\t\t\"sleepingEnemiesMultiplier\": \"Slp\",\r\n\t\t\t\t\t\"environmentMultiplier\": \"Env\",\r\n\t\t\t\t\t\"canPierce\": \"Piercing\",\r\n\t\t\t\t\t\"shortRange\": \"Short Range\",\r\n\t\t\t\t\t\"mediumRange\": \"Medium Range\",\r\n\t\t\t\t\t\"longRange\": \"Long Range\",\r\n\t\t\t\t\t\"hammer\": \"Hammer - Balanced\",\r\n\t\t\t\t\t\"knife\": \"Knife - Fast\",\r\n\t\t\t\t\t\"bat\": \"Bat - Fast\",\r\n\t\t\t\t\t\"spear\": \"Spear - Slow\"\r\n\t\t\t\t},\r\n\t\t\t\t\"spread\": {\r\n\t\t\t\t\t\"chocked\": \"Chocked Spread\",\r\n\t\t\t\t\t\"small\": \"Small Spread\",\r\n\t\t\t\t\t\"medium\": \"Medium Spread\",\r\n\t\t\t\t\t\"large\": \"Large Spread\",\r\n\t\t\t\t\t\"huge\": \"Huge Spread\"\r\n\t\t\t\t},\r\n\t\t\t\t\"sleepers\": {\r\n\t\t\t\t\t\"striker\": \"STRK\",\r\n\t\t\t\t\t\"shooter\": \"SHTR\",\r\n\t\t\t\t\t\"scout\": \"SCOUT\",\r\n\t\t\t\t\t\"bigStriker\": \"B-STRK\",\r\n\t\t\t\t\t\"bigShooter\": \"B-SHTR\",\r\n\t\t\t\t\t\"charger\": \"CHRG\",\r\n\t\t\t\t\t\"chargerScout\": \"C-SCOUT\",\r\n\t\t\t\t\t\"occipit\": \"o\",\r\n\t\t\t\t\t\"head\": \"h\",\r\n\t\t\t\t\t\"back\": \"b\",\r\n\t\t\t\t\t\"chest\": \"c\"\r\n\t\t\t\t},\r\n\t\t\t\t\"damage\": \"Dmg\",\r\n\t\t\t\t\"clip\": \"Clp\",\r\n\t\t\t\t\"maxAmmo\": \"Max\",\r\n\t\t\t\t\"falloff\": \"Dist\",\r\n\t\t\t\t\"reload\": \"Rld\",\r\n\t\t\t\t\"stagger\": \"Stgr\",\r\n\t\t\t\t\"precision\": \"Prcn\",\r\n\t\t\t\t\"pierceCount\": \"Pierc\",\r\n\t\t\t\t\"rateOfFire\": \"RoF\",\r\n\t\t\t\t\"aimDSpread\": \"ADS\",\r\n\t\t\t\t\"hipSpread\": \"HIP\",\r\n\t\t\t\t\"deployable\": \"Deployable\",\r\n\t\t\t\t\"longChargeUp\": \"Long Charge-up\",\r\n\t\t\t\t\"shortChargeUp\": \"short Charge-up\"\r\n\t\t\t},\r\n\r\n\t\t\t\"chinese\": {\r\n\t\t\t\t\"firemode\": {\r\n\t\t\t\t\t\"fullA\": \"全自动\",\r\n\t\t\t\t\t\"semiA\": \"半自动\",\r\n\t\t\t\t\t\"burst\": \"连发\",\r\n\t\t\t\t\t\"shotgunSentry\": \"半自动霰弹射击\"\r\n\t\t\t\t},\r\n\t\t\t\t\"melee\": {\r\n\t\t\t\t\t\"light\": \"轻击\",\r\n\t\t\t\t\t\"heavy\": \"重击\",\r\n\t\t\t\t\t\"canRunWhileCharging\": \"不能冲刺\",\r\n\t\t\t\t\t\"sleepingEnemiesMultiplier\": \"沉睡倍率\",\r\n\t\t\t\t\t\"environmentMultiplier\": \"环境倍率\",\r\n\t\t\t\t\t\"canPierce\": \"穿刺\",\r\n\t\t\t\t\t\"shortRange\": \"短距离\",\r\n\t\t\t\t\t\"mediumRange\": \"中距离\",\r\n\t\t\t\t\t\"longRange\": \"长距离\",\r\n\t\t\t\t\t\"hammer\": \"大锤 - 均衡\",\r\n\t\t\t\t\t\"knife\": \"刀 - 快速\",\r\n\t\t\t\t\t\"bat\": \"棍棒 - 快速\",\r\n\t\t\t\t\t\"spear\": \"矛 - 慢速\"\r\n\t\t\t\t},\r\n\t\t\t\t\"spread\": {\r\n\t\t\t\t\t\"chocked\": \"收束扩散\",\r\n\t\t\t\t\t\"small\": \"扩散小\",\r\n\t\t\t\t\t\"medium\": \"中度扩散\",\r\n\t\t\t\t\t\"large\": \"扩散大\",\r\n\t\t\t\t\t\"huge\": \"超大扩散\"\r\n\t\t\t\t},\r\n\t\t\t\t\"sleepers\": {\r\n\t\t\t\t\t\"striker\": \"前锋\",\r\n\t\t\t\t\t\"shooter\": \"射手\",\r\n\t\t\t\t\t\"scout\": \"哨兵\",\r\n\t\t\t\t\t\"bigStriker\": \"大壮\",\r\n\t\t\t\t\t\"bigShooter\": \"大姐\",\r\n\t\t\t\t\t\"charger\": \"黑刺\",\r\n\t\t\t\t\t\"chargerScout\": \"黑触\",\r\n\t\t\t\t\t\"occipit\": \"后脑\",\r\n\t\t\t\t\t\"head\": \"头\",\r\n\t\t\t\t\t\"back\": \"背\",\r\n\t\t\t\t\t\"chest\": \"胸\"\r\n\t\t\t\t},\r\n\r\n\t\t\t\t\"damage\": \"伤害\",\r\n\t\t\t\t\"clip\": \"弹容量\",\r\n\t\t\t\t\"maxAmmo\": \"总弹量\",\r\n\t\t\t\t\"falloff\": \"衰减距离\",\r\n\t\t\t\t\"reload\": \"换弹时间\",\r\n\t\t\t\t\"stagger\": \"硬直倍率\",\r\n\t\t\t\t\"precision\": \"精准倍率\",\r\n\t\t\t\t\"pierceCount\": \"穿透\",\r\n\t\t\t\t\"rateOfFire\": \"射速\",\r\n\t\t\t\t\"aimDSpread\": \"倍镜\",\r\n\t\t\t\t\"hipSpread\": \"后坐力\",\r\n\t\t\t\t\"deployable\": \"可部署\",\r\n\t\t\t\t\"longChargeUp\": \"长蓄力\",\r\n\t\t\t\t\"shortChargeUp\": \"短蓄力\"\r\n\t\t\t}\r\n\t\t}"; } } namespace WeaponStatShower.Utils.Language.Models { public class FiremodeLanguageModel { public string fullA { get; set; } = string.Empty; public string semiA { get; set; } = string.Empty; public string burst { get; set; } = string.Empty; public string shotgunSentry { get; set; } = string.Empty; } public class MeleeLanguageModel { public string light { get; set; } = string.Empty; public string heavy { get; set; } = string.Empty; public string canRunWhileCharging { get; set; } = string.Empty; public string sleepingEnemiesMultiplier { get; set; } = string.Empty; public string environmentMultiplier { get; set; } = string.Empty; public string canPierce { get; set; } = string.Empty; public string shortRange { get; set; } = string.Empty; public string mediumRange { get; set; } = string.Empty; public string longRange { get; set; } = string.Empty; public string hammer { get; set; } = string.Empty; public string knife { get; set; } = string.Empty; public string bat { get; set; } = string.Empty; public string spear { get; set; } = string.Empty; } public class SleepersLanguageModel { public string striker { get; set; } = string.Empty; public string shooter { get; set; } = string.Empty; public string scout { get; set; } = string.Empty; public string bigStriker { get; set; } = string.Empty; public string bigShooter { get; set; } = string.Empty; public string charger { get; set; } = string.Empty; public string chargerScout { get; set; } = string.Empty; public string occipit { get; set; } = string.Empty; public string head { get; set; } = string.Empty; public string back { get; set; } = string.Empty; public string chest { get; set; } = string.Empty; } public class SpreadLanguageModel { public string chocked { get; set; } = string.Empty; public string small { get; set; } = string.Empty; public string medium { get; set; } = string.Empty; public string large { get; set; } = string.Empty; public string huge { get; set; } = string.Empty; } } namespace WeaponStatShower.Patches { public abstract class Patch { protected internal Harmony? Harmony { get; set; } public virtual string Name { get; } public virtual bool Enabled => true; public virtual void Initialize() { } public abstract void Execute(); public void PatchConstructor(PatchType patchType, string? prefixMethodName = null, string? postfixMethodName = null) where TClass : class { PatchConstructor(null, patchType, prefixMethodName, postfixMethodName); } public void PatchConstructor(Type[]? parameters, PatchType patchType, string? prefixMethodName = null, string? postfixMethodName = null) where TClass : class { ConstructorInfo methodBase = AccessTools.Constructor(typeof(TClass), parameters, false); PatchMethod(methodBase, patchType, prefixMethodName, postfixMethodName); } public void PatchMethod(string methodName, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) where TClass : class { PatchMethod(methodName, null, patchType, generics, prefixMethodName, postfixMethodName); } public void PatchMethod(string methodName, Type[] parameters, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) where TClass : class { MethodInfo methodBase = AccessTools.Method(typeof(TClass), methodName, parameters, generics); PatchMethod(methodBase, patchType, prefixMethodName, postfixMethodName); } public void PatchMethod(MethodBase methodBase, PatchType patchType, string prefixMethodName = null, string postfixMethodName = null) where TClass : class { PatchMethod(typeof(TClass), methodBase, patchType, prefixMethodName, postfixMethodName); } public void PatchMethod(Type classType, string methodName, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) { PatchMethod(classType, methodName, null, patchType, generics, prefixMethodName, postfixMethodName); } public void PatchMethod(Type classType, string methodName, Type[] parameters, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) { MethodInfo methodBase = AccessTools.Method(classType, methodName, parameters, generics); PatchMethod(classType, methodBase, patchType, prefixMethodName, postfixMethodName); } public void PatchMethod(Type classType, MethodBase methodBase, PatchType patchType, string? prefixMethodName = null, string? postfixMethodName = null) { //IL_0162: 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_0175: Expected O, but got Unknown //IL_0175: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown string text = classType.Name.Replace("`", "__"); string value = methodBase.ToString(); string text2 = (methodBase.IsConstructor ? "ctor" : methodBase.Name); MethodInfo methodInfo = null; MethodInfo methodInfo2 = null; if ((patchType & PatchType.Prefix) != 0) { try { methodInfo2 = AccessTools.Method(GetType(), prefixMethodName ?? (text + "__" + text2 + "__Prefix"), (Type[])null, (Type[])null); } catch (Exception value2) { WeaponStatShowerPlugin.LogFatal($"Failed to obtain the prefix patch method for {value}): {value2}"); } } if ((patchType & PatchType.Postfix) != 0) { try { methodInfo = AccessTools.Method(GetType(), postfixMethodName ?? (text + "__" + text2 + "__Postfix"), (Type[])null, (Type[])null); } catch (Exception value3) { WeaponStatShowerPlugin.LogFatal($"Failed to obtain the postfix patch method for {value}): {value3}"); } } try { if (methodInfo2 != null && methodInfo != null) { Harmony.Patch(methodBase, new HarmonyMethod(methodInfo2), new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (methodInfo2 != null) { Harmony.Patch(methodBase, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else if (methodInfo != null) { Harmony.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception value4) { WeaponStatShowerPlugin.LogError($"Failed to patch method {value}: {value4}"); } } } [Flags] public enum PatchType : byte { Prefix = 1, Postfix = 2, Both = 3 } internal class ShowStat : Patch { private static readonly ConfigDefinition ConfigEnabled = new ConfigDefinition("ShowStat", "Enabled"); private static readonly ConfigDefinition Language = new ConfigDefinition("ShowStat", "Language"); private static readonly ConfigDefinition ConfigSleepers = new ConfigDefinition("ShowStat", "SleepersShown"); private static readonly ConfigDefinition ShowStats = new ConfigDefinition("ShowStat", "ShowStats"); private static readonly ConfigDefinition ShowDescription = new ConfigDefinition("ShowStat", "ShowDescription"); private static WeaponDescriptionBuilder? DescriptionBuilder; private static LanguageEnum PrevLanguageEnum = LanguageEnum.English; private static string PrevShownSleepers = "PLACEHOLDER"; private const string PatchName = "ShowStat"; private const PatchType patchType = PatchType.Postfix; public override string Name { get; } = "ShowStat"; public static Patch Instance { get; private set; } public override void Initialize() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown Instance = this; ((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind(ConfigEnabled, true, new ConfigDescription("Show the stats of a weapon.", (AcceptableValueBase)null, Array.Empty())); ((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind(Language, LanguageEnum.English, new ConfigDescription("Select the mod language.", (AcceptableValueBase)null, Array.Empty())); ((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind(ConfigSleepers, "NONE", new ConfigDescription("Select which Sleepers are shown, seperated by a comma.\nAcceptable values: ALL, NONE, STRIKER, SHOOTER, SCOUT, BIG_STRIKER, BIG_SHOOTER, CHARGER, CHARGER_SCOUT", (AcceptableValueBase)null, Array.Empty())); ((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind(ShowStats, true, new ConfigDescription("Show auto-generated weapon stats.", (AcceptableValueBase)null, Array.Empty())); ((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind(ShowDescription, true, new ConfigDescription("Show gear descriptions alongside stats and enemy killpoints (if enabled).", (AcceptableValueBase)null, Array.Empty())); DescriptionBuilder = new WeaponDescriptionBuilder(); } public override void Execute() { PatchMethod("LoadData", PatchType.Postfix); } public static void CM_InventorySlotItem__LoadData__Postfix(CM_InventorySlotItem __instance, GearIDRange idRange, bool clickable, bool detailedInfo) { if ((Object)(object)__instance == (Object)null || !detailedInfo) { return; } if (DescriptionBuilder == null) { WeaponStatShowerPlugin.LogError("Something went wrong with the DescriptionBuilder"); return; } ((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Reload(); ConfigFile config = ((BasePlugin)WeaponStatShowerPlugin.Instance).Config; string text = config.GetConfigEntry(ConfigSleepers).Value.Trim().ToUpper(); LanguageEnum value = config.GetConfigEntry(Language).Value; bool value2 = config.GetConfigEntry(ShowStats).Value; bool value3 = config.GetConfigEntry(ShowDescription).Value; if (!PrevShownSleepers.Equals(text) || !value.Equals(PrevLanguageEnum)) { DescriptionBuilder.UpdateSleepersDatas(text.Split(','), value); PrevShownSleepers = text; PrevLanguageEnum = value; } DescriptionBuilder.Inizialize(idRange, GameDataBlockBase.GetBlock(1u), value, value2, value3); if (value3) { string text2 = DescriptionBuilder.DescriptionFormatter(__instance.GearDescription); if (!Utility.IsNullOrWhiteSpace(text2)) { text2 += "\n"; } __instance.GearDescription = text2 + __instance.GearDescription; } __instance.GearPublicName = DescriptionBuilder.FireRateFormatter(__instance.GearPublicName); } } }