Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of MercExtraEffects v1.1.0
BepInEx/plugins/MercExtraEffects/MercExtraEffects.dll
Decompiled 3 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Merc; using On.EntityStates.Merc; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Skills; using UnityEngine; using UnityEngine.AddressableAssets; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ExamplePlugin")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ExamplePlugin")] [assembly: AssemblyTitle("ExamplePlugin")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace ExamplePlugin; [BepInPlugin("com.fafnir62.mercenary_extra_effects", "Mercenary Extra Effects", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class MercExtraEffectsPlugin : BaseUnityPlugin { private class MercTracker : MonoBehaviour { public bool uppercutActive; public bool whirlwindActive; public bool evisActive; } public const string PluginGUID = "com.fafnir62.mercenary_extra_effects"; public const string PluginName = "Mercenary Extra Effects"; public const string PluginVersion = "1.1.0"; private static BodyIndex mercBodyIndex = (BodyIndex)(-1); private static ConfigEntry<float> cfgSecondaryLifestealPercent; private static ConfigEntry<float> cfgEvisBarrierPercent; private static ConfigEntry<float> cfgFocusedAssaultDamagePercent; private static ConfigEntry<float> cfgFocusedAssaultCooldownSeconds; private static ConfigEntry<float> cfgEvisDamagePercent; private static ConfigEntry<float> cfgEvisCooldownSeconds; private const float UtilityCooldownSeconds = 6f; private const string FocusedAssaultSkillDefPath = "RoR2/Base/Merc/MercBodyFocusedAssault.asset"; private static readonly string[] EvisSkillDefPaths = new string[3] { "RoR2/Base/Merc/MercBodyEviscerate.asset", "RoR2/Base/Merc/MercBodyEvis.asset", "RoR2/Base/Merc/MercBodySpecialEviscerate.asset" }; private bool _inRiskOfOptionsSetup; private bool _suppressSettingChanged; private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[MercExtraEffects] Awake"); InitConfig(); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnGameLoaded)); } private void OnGameLoaded() { //IL_0006: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown mercBodyIndex = BodyCatalog.FindBodyIndex("MercBody"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MercExtraEffects] MercBodyIndex=" + ((object)(BodyIndex)(ref mercBodyIndex)).ToString())); CharacterBody.onBodyStartGlobal += OnBodyStart; Uppercut.OnEnter += new hook_OnEnter(Uppercut_OnEnter); Uppercut.OnExit += new hook_OnExit(Uppercut_OnExit); WhirlwindBase.OnEnter += new hook_OnEnter(WhirlwindBase_OnEnter); WhirlwindBase.OnExit += new hook_OnExit(WhirlwindBase_OnExit); Evis.OnEnter += new hook_OnEnter(Evis_OnEnter); Evis.OnExit += new hook_OnExit(Evis_OnExit); FocusedAssaultDash.AuthorityModifyOverlapAttack += new hook_AuthorityModifyOverlapAttack(FocusedAssaultDash_AuthorityModifyOverlapAttack); GlobalEventManager.onServerDamageDealt += OnServerDamageDealt; TrySetMercUtilityCooldownFromBodyPrefab(6f); ApplySkillTuning(); } private void InitConfig() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown cfgSecondaryLifestealPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Merc", "Secondary Lifesteal (%)", 20f, new ConfigDescription("How much of damage dealt is healed while Merc M2 (Uppercut/Whirlwind) is active.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>())); cfgEvisBarrierPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Merc", "Evis Barrier Per Hit (%)", 3f, new ConfigDescription("Barrier gained per hit while Eviscerate is active, as % of max combined health.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); cfgFocusedAssaultDamagePercent = ((BaseUnityPlugin)this).Config.Bind<float>("Merc", "Focused Assault Damage (%)", 700f, new ConfigDescription("Focused Assault damage per dash hit (vanilla 700%). Example: 700 = 700%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5000f), Array.Empty<object>())); cfgFocusedAssaultCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Merc", "Focused Assault Cooldown (s)", 8f, new ConfigDescription("Focused Assault base cooldown in seconds (vanilla 8).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>())); cfgEvisDamagePercent = ((BaseUnityPlugin)this).Config.Bind<float>("Merc", "Eviscerate Damage (%)", 110f, new ConfigDescription("Eviscerate damage per hit (vanilla 110%). Example: 110 = 110%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5000f), Array.Empty<object>())); cfgEvisCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Merc", "Eviscerate Cooldown (s)", 6f, new ConfigDescription("Eviscerate base cooldown in seconds (vanilla 6). Requires game restart after editing config file.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>())); ((BaseUnityPlugin)this).Config.SettingChanged += OnAnyConfigSettingChanged; try { _inRiskOfOptionsSetup = true; ModSettingsManager.SetModDescription("Merc skill effects.\n\nThis mod is configured via the BepInEx config file only.\nValues shown here are read-only to avoid confusing clients."); AddReadOnlySlider(cfgSecondaryLifestealPercent, 0f, 100f, 1f); AddReadOnlySlider(cfgEvisBarrierPercent, 0f, 100f, 0.5f); AddReadOnlySlider(cfgFocusedAssaultDamagePercent, 0f, 5000f, 50f); AddReadOnlySlider(cfgFocusedAssaultCooldownSeconds, 0f, 30f, 0.5f); AddReadOnlySlider(cfgEvisDamagePercent, 0f, 5000f, 10f); AddReadOnlySlider(cfgEvisCooldownSeconds, 0f, 30f, 0.5f); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MercExtraEffects] RiskOfOptions UI not available: " + ex.Message)); } finally { _inRiskOfOptionsSetup = false; } } private void AddReadOnlySlider(ConfigEntry<float> entry, float min, float max, float increment) { //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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new StepSliderOption(entry, new StepSliderConfig { min = min, max = max, increment = increment })); } private void OnAnyConfigSettingChanged(object sender, SettingChangedEventArgs e) { if (_suppressSettingChanged || e == null || e.ChangedSetting == null) { return; } try { if ((e.ChangedSetting == cfgSecondaryLifestealPercent || e.ChangedSetting == cfgEvisBarrierPercent || e.ChangedSetting == cfgFocusedAssaultDamagePercent || e.ChangedSetting == cfgFocusedAssaultCooldownSeconds || e.ChangedSetting == cfgEvisDamagePercent || e.ChangedSetting == cfgEvisCooldownSeconds) && !_inRiskOfOptionsSetup) { _suppressSettingChanged = true; ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[MercExtraEffects] In-game config change detected and reverted. Edit the config file + restart to apply."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] Failed to revert in-game config change: " + ex)); } finally { _suppressSettingChanged = false; } } private static bool IsMerc(CharacterBody body) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return (Object)(object)body != (Object)null && body.bodyIndex == mercBodyIndex; } private void OnBodyStart(CharacterBody body) { if (!((Object)(object)body == (Object)null) && (Object)(object)((Component)body).GetComponent<MercTracker>() == (Object)null) { ((Component)body).gameObject.AddComponent<MercTracker>(); } } private static MercTracker GetTracker(CharacterBody body) { return ((Object)(object)body != (Object)null) ? ((Component)body).GetComponent<MercTracker>() : null; } private void Uppercut_OnEnter(orig_OnEnter orig, Uppercut self) { orig.Invoke(self); CharacterBody characterBody = ((EntityState)self).characterBody; if (IsMerc(characterBody)) { MercTracker tracker = GetTracker(characterBody); if ((Object)(object)tracker != (Object)null) { tracker.uppercutActive = true; } } } private void Uppercut_OnExit(orig_OnExit orig, Uppercut self) { CharacterBody characterBody = ((EntityState)self).characterBody; if (IsMerc(characterBody)) { MercTracker tracker = GetTracker(characterBody); if ((Object)(object)tracker != (Object)null) { tracker.uppercutActive = false; } } orig.Invoke(self); } private void WhirlwindBase_OnEnter(orig_OnEnter orig, WhirlwindBase self) { orig.Invoke(self); CharacterBody characterBody = ((EntityState)self).characterBody; if (IsMerc(characterBody)) { MercTracker tracker = GetTracker(characterBody); if ((Object)(object)tracker != (Object)null) { tracker.whirlwindActive = true; } } } private void WhirlwindBase_OnExit(orig_OnExit orig, WhirlwindBase self) { CharacterBody characterBody = ((EntityState)self).characterBody; if (IsMerc(characterBody)) { MercTracker tracker = GetTracker(characterBody); if ((Object)(object)tracker != (Object)null) { tracker.whirlwindActive = false; } } orig.Invoke(self); } private void Evis_OnEnter(orig_OnEnter orig, Evis self) { orig.Invoke(self); CharacterBody characterBody = ((EntityState)self).characterBody; if (IsMerc(characterBody)) { MercTracker tracker = GetTracker(characterBody); if ((Object)(object)tracker != (Object)null) { tracker.evisActive = true; } } } private void Evis_OnExit(orig_OnExit orig, Evis self) { CharacterBody characterBody = ((EntityState)self).characterBody; if (IsMerc(characterBody)) { MercTracker tracker = GetTracker(characterBody); if ((Object)(object)tracker != (Object)null) { tracker.evisActive = false; } } orig.Invoke(self); } private void FocusedAssaultDash_AuthorityModifyOverlapAttack(orig_AuthorityModifyOverlapAttack orig, FocusedAssaultDash self, OverlapAttack overlapAttack) { orig.Invoke(self, overlapAttack); try { if (self != null && overlapAttack != null) { float num = Mathf.Clamp(cfgFocusedAssaultDamagePercent.Value, 0f, 5000f) / 100f; overlapAttack.damage = ((BaseState)self).damageStat * num; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] FocusedAssaultDash_AuthorityModifyOverlapAttack error: " + ex)); } } private void OnServerDamageDealt(DamageReport report) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) try { if (report == null) { return; } CharacterBody attackerBody = report.attackerBody; if (!IsMerc(attackerBody)) { return; } MercTracker tracker = GetTracker(attackerBody); if ((Object)(object)tracker == (Object)null) { return; } HealthComponent healthComponent = attackerBody.healthComponent; if (!Object.op_Implicit((Object)(object)healthComponent)) { return; } float damageDealt = report.damageDealt; if (damageDealt <= 0f) { return; } if (tracker.uppercutActive || tracker.whirlwindActive) { float num = Mathf.Clamp(cfgSecondaryLifestealPercent.Value, 0f, 200f) / 100f; float num2 = damageDealt * num; if (num2 > 0f) { healthComponent.Heal(num2, default(ProcChainMask), true); } } if (tracker.evisActive) { float num3 = Mathf.Clamp(cfgEvisBarrierPercent.Value, 0f, 100f) / 100f; float num4 = healthComponent.fullCombinedHealth * num3; if (num4 > 0f) { healthComponent.AddBarrier(num4); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] OnServerDamageDealt error: " + ex)); } } private void TrySetMercUtilityCooldownFromBodyPrefab(float cooldownSeconds) { try { GameObject val = BodyCatalog.FindBodyPrefab("MercBody"); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MercExtraEffects] Could not find MercBody prefab to set utility cooldown."); return; } SkillLocator component = val.GetComponent<SkillLocator>(); if ((Object)(object)component == (Object)null || (Object)(object)component.utility == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MercExtraEffects] MercBody SkillLocator or utility slot not found."); return; } SkillDef skillDef = component.utility.skillDef; if ((Object)(object)skillDef == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MercExtraEffects] Merc utility SkillDef not found."); return; } float baseRechargeInterval = skillDef.baseRechargeInterval; skillDef.baseRechargeInterval = cooldownSeconds; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MercExtraEffects] Utility cooldown changed: " + baseRechargeInterval + " -> " + skillDef.baseRechargeInterval)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] Failed to set utility cooldown: " + ex)); } } private void ApplySkillTuning() { ApplyFocusedAssaultCooldown(); ApplyEvisDamageCoefficient(); ApplyEvisCooldown(); } private void ApplyFocusedAssaultCooldown() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) try { float baseRechargeInterval = Mathf.Clamp(cfgFocusedAssaultCooldownSeconds.Value, 0f, 60f); SkillDef val = Addressables.LoadAssetAsync<SkillDef>((object)"RoR2/Base/Merc/MercBodyFocusedAssault.asset").WaitForCompletion(); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MercExtraEffects] Focused Assault SkillDef not found at: RoR2/Base/Merc/MercBodyFocusedAssault.asset"); return; } float baseRechargeInterval2 = val.baseRechargeInterval; val.baseRechargeInterval = baseRechargeInterval; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MercExtraEffects] Focused Assault cooldown changed: " + baseRechargeInterval2 + " -> " + val.baseRechargeInterval)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] Failed to set Focused Assault cooldown: " + ex)); } } private void ApplyEvisDamageCoefficient() { try { float value = Mathf.Clamp(cfgEvisDamagePercent.Value, 0f, 5000f) / 100f; if (!TrySetStaticFloat(typeof(Evis), "damageCoefficient", value)) { TrySetStaticFloat(typeof(Evis), "baseDamageCoefficient", value); TrySetStaticFloat(typeof(Evis), "damageCoefficientPerHit", value); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] Failed to set Evis damage coefficient: " + ex)); } } private void ApplyEvisCooldown() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) try { float baseRechargeInterval = Mathf.Clamp(cfgEvisCooldownSeconds.Value, 0f, 60f); SkillDef val = null; string[] evisSkillDefPaths = EvisSkillDefPaths; foreach (string text in evisSkillDefPaths) { try { val = Addressables.LoadAssetAsync<SkillDef>((object)text).WaitForCompletion(); if ((Object)(object)val != (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MercExtraEffects] Found Evis SkillDef at: " + text)); break; } } catch { } } if ((Object)(object)val == (Object)null) { val = FindMercSpecialSkillDefByState(typeof(EvisDash)) ?? FindMercSpecialSkillDefByState(typeof(Evis)); } if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"[MercExtraEffects] Could not find Eviscerate SkillDef to set cooldown. (Tried addressables + MercBody scan)"); return; } float baseRechargeInterval2 = val.baseRechargeInterval; val.baseRechargeInterval = baseRechargeInterval; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[MercExtraEffects] Eviscerate cooldown changed: " + baseRechargeInterval2 + " -> " + val.baseRechargeInterval)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("[MercExtraEffects] Failed to set Eviscerate cooldown: " + ex)); } } private SkillDef FindMercSpecialSkillDefByState(Type targetStateType) { try { GameObject val = BodyCatalog.FindBodyPrefab("MercBody"); if ((Object)(object)val == (Object)null) { return null; } SkillLocator component = val.GetComponent<SkillLocator>(); if ((Object)(object)component == (Object)null || (Object)(object)component.special == (Object)null) { return null; } SkillDef skillDef = component.special.skillDef; if ((Object)(object)skillDef == (Object)null) { return null; } if (((SerializableEntityStateType)(ref skillDef.activationState)).stateType == targetStateType) { return skillDef; } return null; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[MercExtraEffects] FindMercSpecialSkillDefByState error: " + ex.Message)); return null; } } private bool TrySetStaticFloat(Type type, string fieldName, float value) { try { FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return false; } if (field.FieldType != typeof(float)) { return false; } float num = (float)field.GetValue(null); field.SetValue(null, value); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[MercExtraEffects] {type.Name}.{fieldName} changed: {num} -> {value}"); return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[MercExtraEffects] Failed setting " + type.Name + "." + fieldName + ": " + ex.Message)); return false; } } } internal static class Log { private static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } }