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<T> GetConfigEntry<T>(this ConfigFile configFile, ConfigDefinition definition)
{
ConfigEntry<T> result = default(ConfigEntry<T>);
if (!configFile.TryGetEntry<T>(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<Type, Patch> RegisteredPatches = new Dictionary<Type, Patch>();
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<ShowStat>();
((BasePlugin)this).Config.Save();
}
public static void RegisterPatch<T>() 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<ArchetypeDataBlock>.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<ArchetypeDataBlock>.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<string, EnemyData> _enemyDatas = new Dictionary<string, EnemyData>();
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<string, EnemyData, float> getDamage)
{
StringBuilder stringBuilder = new StringBuilder();
int num = 0;
int num2 = 0;
int num3 = _enemyDatas.Count - 1;
foreach (KeyValuePair<string, EnemyData> enemyData2 in _enemyDatas)
{
enemyData2.Deconstruct(out var key, out var value);
string text = key;
EnemyData enemyData = value;
float damage = getDamage(text, enemyData);
List<string> list = new List<string>(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 = "</color>";
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<GearCategoryDataBlock>.GetBlock(_categoryID);
_itemDB = GameDataBlockBase<ItemDataBlock>.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<LanguageDatasClass>(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<MeleeArchetypeDataBlock>.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<MeleeArchetypeDataBlock>.GetBlock(GearBuilder.GetMeleeArchetypeID(_gearCategoryDB));
MeleeLanguageModel melee = _languageDatas.melee;
return ((GameDataBlockBase<MeleeArchetypeDataBlock>)(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("</color>");
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("</color>");
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("</color>");
handler.AppendFormatted(" | ");
handler.AppendLiteral("<#12FF50>");
handler.AppendFormatted(_languageDatas.rateOfFire);
handler.AppendLiteral(" ");
handler.AppendFormatted(GetRateOfFire(archetypeDB, fireMode));
handler.AppendFormatted("</color>");
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("</color>");
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("</color>");
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("</color>");
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, "<color=orange>", _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, "<color=green>", _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, "<color=orange>", _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, "<color=green>", _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("</color>");
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<TClass>(PatchType patchType, string? prefixMethodName = null, string? postfixMethodName = null) where TClass : class
{
PatchConstructor<TClass>(null, patchType, prefixMethodName, postfixMethodName);
}
public void PatchConstructor<TClass>(Type[]? parameters, PatchType patchType, string? prefixMethodName = null, string? postfixMethodName = null) where TClass : class
{
ConstructorInfo methodBase = AccessTools.Constructor(typeof(TClass), parameters, false);
PatchMethod<TClass>(methodBase, patchType, prefixMethodName, postfixMethodName);
}
public void PatchMethod<TClass>(string methodName, PatchType patchType, Type[] generics = null, string prefixMethodName = null, string postfixMethodName = null) where TClass : class
{
PatchMethod<TClass>(methodName, null, patchType, generics, prefixMethodName, postfixMethodName);
}
public void PatchMethod<TClass>(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<TClass>(methodBase, patchType, prefixMethodName, postfixMethodName);
}
public void PatchMethod<TClass>(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<bool>(ConfigEnabled, true, new ConfigDescription("Show the stats of a weapon.", (AcceptableValueBase)null, Array.Empty<object>()));
((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind<LanguageEnum>(Language, LanguageEnum.English, new ConfigDescription("Select the mod language.", (AcceptableValueBase)null, Array.Empty<object>()));
((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind<string>(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<object>()));
((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind<bool>(ShowStats, true, new ConfigDescription("Show auto-generated weapon stats.", (AcceptableValueBase)null, Array.Empty<object>()));
((BasePlugin)WeaponStatShowerPlugin.Instance).Config.Bind<bool>(ShowDescription, true, new ConfigDescription("Show gear descriptions alongside stats and enemy killpoints (if enabled).", (AcceptableValueBase)null, Array.Empty<object>()));
DescriptionBuilder = new WeaponDescriptionBuilder();
}
public override void Execute()
{
PatchMethod<CM_InventorySlotItem>("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<string>(ConfigSleepers).Value.Trim().ToUpper();
LanguageEnum value = config.GetConfigEntry<LanguageEnum>(Language).Value;
bool value2 = config.GetConfigEntry<bool>(ShowStats).Value;
bool value3 = config.GetConfigEntry<bool>(ShowDescription).Value;
if (!PrevShownSleepers.Equals(text) || !value.Equals(PrevLanguageEnum))
{
DescriptionBuilder.UpdateSleepersDatas(text.Split(','), value);
PrevShownSleepers = text;
PrevLanguageEnum = value;
}
DescriptionBuilder.Inizialize(idRange, GameDataBlockBase<PlayerDataBlock>.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);
}
}
}