Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SparkleHuntressTweaks v1.6.0
plugins/SparkleHuntressTweaks.dll
Decompiled 20 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using EntityStates.Huntress; using EntityStates.Huntress.HuntressWeapon; using HarmonyLib; using Microsoft.CodeAnalysis; using R2API; using RoR2; using RoR2.Projectile; using RoR2.Skills; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("SparkleHuntressTweaks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.6.0.0")] [assembly: AssemblyInformationalVersion("1.6.0")] [assembly: AssemblyProduct("SparkleHuntressTweaks")] [assembly: AssemblyTitle("SparkleHuntressTweaks")] [assembly: AssemblyVersion("1.6.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SparkleHuntressTweaks { internal static class HuntressArrowRainTweaks { private const string SectionName = "ArrowRain.箭雨"; private const string ProjectileName = "HuntressArrowRain"; private const float FallbackOverlapCoefficient = 0.5f; private const float AimMaxDistance = 1000f; private static ManualLogSource _log; private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _damageCoefficientPerTick; private static ConfigEntry<float> _procCoefficient; private static ConfigEntry<bool> _allowEnemyTargeting; private static ConfigEntry<float> _enemyAimAssistRadius; private static readonly MethodInfo GetAimRayMethod = AccessTools.Method(typeof(BaseState), "GetAimRay", (Type[])null, (Type[])null); private static readonly FieldInfo AreaIndicatorField = AccessTools.Field(typeof(ArrowRain), "areaIndicatorInstance"); private static readonly FieldInfo AttackField = AccessTools.Field(typeof(ProjectileOverlapAttack), "attack"); private static readonly FieldInfo ProjectileControllerField = AccessTools.Field(typeof(ProjectileOverlapAttack), "projectileController"); private static readonly FieldInfo ControllerProcField = AccessTools.Field(typeof(ProjectileController), "procCoefficient"); private static float _vanillaStateCoefficient = -1f; private static bool _loggedDamage; private static bool _loggedProc; private static bool _loggedTargeting; internal static void Init(ConfigFile config, ManualLogSource log) { _log = log; _enabled = config.Bind<bool>("ArrowRain.箭雨", "Enabled", true, "是否启用女猎人 R「箭雨」的调整(伤害倍率 / 触发系数 / 可对敌人释放)。"); _damageCoefficientPerTick = config.Bind<float>("ArrowRain.箭雨", "DamageCoefficientPerTick", 1.5f, "箭雨每段伤害倍率。1.5 = 150% 攻击力;原版为 1.1。"); _procCoefficient = config.Bind<float>("ArrowRain.箭雨", "ProcCoefficient", 0.5f, "箭雨的触发系数。0.5 = 50%;原版为 0.2。"); _allowEnemyTargeting = config.Bind<bool>("ArrowRain.箭雨", "AllowEnemyTargeting", true, "是否允许把箭雨的落点瞄准在敌人身上(原版只能瞄地形)。"); _enemyAimAssistRadius = config.Bind<float>("ArrowRain.箭雨", "EnemyAimAssistRadius", 1f, "瞄敌人的球形辅助半径:射线没打中时再按这个半径做一次球形扫描,0 = 关闭。"); } internal static void Patch(Harmony harmony) { MethodInfo methodInfo = AccessTools.Method(typeof(ArrowRain), "DoFireArrowRain", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, PatchMethod("Prefix_DoFireArrowRain"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)("补丁已挂载:ArrowRain.DoFireArrowRain <- Prefix_DoFireArrowRain() [target=" + (methodInfo != null) + "]")); MethodInfo methodInfo2 = AccessTools.Method(typeof(ProjectileOverlapAttack), "Start", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, PatchMethod("Postfix_ProjectileOverlapAttackStart"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)("补丁已挂载:ProjectileOverlapAttack.Start <- Postfix_ProjectileOverlapAttackStart() [target=" + (methodInfo2 != null) + "]")); MethodInfo methodInfo3 = AccessTools.Method(typeof(ProjectileOverlapAttack), "OnEnable", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, PatchMethod("Postfix_ProjectileOverlapAttackEnable"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)("补丁已挂载:ProjectileOverlapAttack.OnEnable <- Postfix_ProjectileOverlapAttackEnable() [target=" + (methodInfo3 != null) + "]")); MethodInfo methodInfo4 = AccessTools.Method(typeof(ArrowRain), "UpdateAreaIndicator", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, PatchMethod("Postfix_UpdateAreaIndicator"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)("补丁已挂载:ArrowRain.UpdateAreaIndicator <- Postfix_UpdateAreaIndicator() [target=" + (methodInfo4 != null) + "]")); } private static HarmonyMethod PatchMethod(string name) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new HarmonyMethod(typeof(HuntressArrowRainTweaks).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic)); } private static void Prefix_DoFireArrowRain() { if (!_enabled.Value) { return; } try { float projectileOverlapCoefficient = GetProjectileOverlapCoefficient(); float damageCoefficient = ArrowRain.damageCoefficient; if (_vanillaStateCoefficient < 0f) { _vanillaStateCoefficient = damageCoefficient; } float value = _damageCoefficientPerTick.Value; float num = (ArrowRain.damageCoefficient = value / ((projectileOverlapCoefficient > 0f) ? projectileOverlapCoefficient : 0.5f)); GameObject projectilePrefab = ArrowRain.projectilePrefab; if ((Object)(object)projectilePrefab != (Object)null) { ProjectileOverlapAttack component = projectilePrefab.GetComponent<ProjectileOverlapAttack>(); if ((Object)(object)component != (Object)null) { component.overlapProcCoefficient = _procCoefficient.Value; } } if (!_loggedDamage) { _loggedDamage = true; _log.LogInfo((object)("箭雨伤害:原版每段 " + _vanillaStateCoefficient * projectileOverlapCoefficient + " -> " + value + "(状态系数 " + _vanillaStateCoefficient + " -> " + num + ",射弹重叠系数 " + projectileOverlapCoefficient + ")")); } } catch (Exception ex) { _log.LogError((object)("箭雨伤害调整异常: " + ex)); } } private static float GetProjectileOverlapCoefficient() { GameObject projectilePrefab = ArrowRain.projectilePrefab; if ((Object)(object)projectilePrefab != (Object)null) { ProjectileOverlapAttack component = projectilePrefab.GetComponent<ProjectileOverlapAttack>(); if ((Object)(object)component != (Object)null && component.damageCoefficient > 0f) { return component.damageCoefficient; } } return 0.5f; } private static void Postfix_ProjectileOverlapAttackStart(ProjectileOverlapAttack __instance) { if (!_enabled.Value || (Object)(object)__instance == (Object)null || !IsArrowRainProjectile(__instance)) { return; } try { __instance.overlapProcCoefficient = _procCoefficient.Value; __instance.UpdateAttackValues(); if (!_loggedProc) { _loggedProc = true; _log.LogInfo((object)("箭雨触发系数:0.2 -> " + _procCoefficient.Value + "(已应用到射弹 " + ((Object)((Component)__instance).gameObject).name + ")")); } } catch (Exception ex) { _log.LogError((object)("箭雨触发系数调整异常(Start): " + ex)); } } private static void Postfix_ProjectileOverlapAttackEnable(ProjectileOverlapAttack __instance) { if (!_enabled.Value || (Object)(object)__instance == (Object)null || !IsArrowRainProjectile(__instance)) { return; } try { __instance.overlapProcCoefficient = _procCoefficient.Value; object? value = AttackField.GetValue(__instance); OverlapAttack val = (OverlapAttack)((value is OverlapAttack) ? value : null); if (val != null) { float num = 1f; object? value2 = ProjectileControllerField.GetValue(__instance); ProjectileController val2 = (ProjectileController)((value2 is ProjectileController) ? value2 : null); if ((Object)(object)val2 != (Object)null) { num = val2.procCoefficient; } val.procCoefficient = _procCoefficient.Value * num; } } catch (Exception ex) { _log.LogError((object)("箭雨触发系数调整异常(OnEnable): " + ex)); } } private static bool IsArrowRainProjectile(ProjectileOverlapAttack attack) { if ((Object)(object)((Component)attack).gameObject == (Object)null) { return false; } string name = ((Object)((Component)attack).gameObject).name; if (!string.IsNullOrEmpty(name)) { return name.StartsWith("HuntressArrowRain", StringComparison.Ordinal); } return false; } private static void Postfix_UpdateAreaIndicator(ArrowRain __instance) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) if (!_enabled.Value || !_allowEnemyTargeting.Value || __instance == null) { return; } try { object? value = AreaIndicatorField.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null || !TryGetAimRay(__instance, out var aimRay)) { return; } Ray val2 = aimRay; LayerIndex val3 = LayerIndex.world; RaycastHit val4 = default(RaycastHit); bool flag = Physics.Raycast(val2, ref val4, 1000f, LayerMask.op_Implicit(((LayerIndex)(ref val3)).mask), (QueryTriggerInteraction)0); val3 = LayerIndex.entityPrecise; int num = LayerMask.op_Implicit(((LayerIndex)(ref val3)).mask); val3 = LayerIndex.playerBody; int num2 = num | LayerMask.op_Implicit(((LayerIndex)(ref val3)).mask); val3 = LayerIndex.enemyBody; int num3 = num2 | LayerMask.op_Implicit(((LayerIndex)(ref val3)).mask); RaycastHit hit = default(RaycastHit); bool flag2 = Physics.Raycast(aimRay, ref hit, 1000f, num3, (QueryTriggerInteraction)0); if (!flag2 && _enemyAimAssistRadius.Value > 0f) { flag2 = Physics.SphereCast(aimRay, _enemyAimAssistRadius.Value, ref hit, 1000f, num3, (QueryTriggerInteraction)0); } if (!flag2 || (flag && ((RaycastHit)(ref val4)).distance <= ((RaycastHit)(ref hit)).distance)) { return; } CharacterBody val5 = FindTargetBody(hit); if ((Object)(object)val5 == (Object)null) { return; } CharacterBody val6 = (((Object)(object)((EntityState)__instance).outer != (Object)null) ? ((Component)((EntityState)__instance).outer).GetComponent<CharacterBody>() : null); if (!((Object)(object)val6 != (Object)null) || !((Object)(object)val5 == (Object)(object)val6)) { val.transform.position = val5.corePosition; val.transform.up = Vector3.up; if (!_loggedTargeting) { _loggedTargeting = true; _log.LogInfo((object)("箭雨可对敌人释放:落点已吸附到 " + ((Object)val5).name)); } } } catch (Exception ex) { _log.LogError((object)("箭雨瞄敌异常: " + ex)); } } private static CharacterBody FindTargetBody(RaycastHit hit) { if ((Object)(object)((RaycastHit)(ref hit)).collider == (Object)null) { return null; } HurtBox component = ((Component)((RaycastHit)(ref hit)).collider).GetComponent<HurtBox>(); if ((Object)(object)component != (Object)null && (Object)(object)component.healthComponent != (Object)null) { return component.healthComponent.body; } CharacterBody componentInParent = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<CharacterBody>(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } HealthComponent componentInParent2 = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<HealthComponent>(); if (!((Object)(object)componentInParent2 != (Object)null)) { return null; } return componentInParent2.body; } private static bool TryGetAimRay(ArrowRain state, out Ray aimRay) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) aimRay = default(Ray); try { if (GetAimRayMethod != null) { object obj = GetAimRayMethod.Invoke(state, null); if (obj is Ray) { aimRay = (Ray)obj; return true; } } } catch (Exception ex) { _log.LogWarning((object)("GetAimRay 反射调用失败,改用 InputBankTest: " + ex.Message)); } if ((Object)(object)((EntityState)state).outer == (Object)null) { return false; } InputBankTest component = ((Component)((EntityState)state).outer).GetComponent<InputBankTest>(); if ((Object)(object)component == (Object)null) { return false; } aimRay = new Ray(component.aimOrigin, component.aimDirection); return true; } } internal static class HuntressBlinkTweaks { private const string HuntressBodyName = "HuntressBody"; private const string BlinkSkillNameToken = "HUNTRESS_UTILITY_NAME"; private const string BlinkStateTypeName = "EntityStates.Huntress.BlinkState"; private static ManualLogSource _log; private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _distanceMultiplier; private static ConfigEntry<float> _cooldown; private static bool _cooldownPatched; private static bool _loggedDistance; internal static void Init(ConfigFile config, ManualLogSource log) { _log = log; _enabled = config.Bind<bool>("Blink.闪现", "Enabled", true, "是否启用女猎人 Shift「闪现」的调整(位移缩短 + 冷却降低)。"); _distanceMultiplier = config.Bind<float>("Blink.闪现", "DistanceMultiplier", 0.67f, "闪现位移距离的倍率。0.67 = 缩短 33%;1 = 原版。"); _cooldown = config.Bind<float>("Blink.闪现", "Cooldown", 4f, "闪现的冷却时间(秒)。原版 7 秒;设为 7 即恢复原版。"); } internal static void Patch(Harmony harmony) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown MethodInfo method = typeof(BlinkState).GetMethod("OnEnter", BindingFlags.Instance | BindingFlags.Public); MethodInfo method2 = typeof(HuntressBlinkTweaks).GetMethod("OnEnterPostfix", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)("补丁已挂载 EntityStates.Huntress.BlinkState.OnEnter [target=" + (method != null) + "]")); } private static void OnEnterPostfix(BlinkState __instance) { if (!_enabled.Value || __instance == null || ((object)__instance).GetType() != typeof(BlinkState)) { return; } float value = _distanceMultiplier.Value; if (!(Math.Abs(value - 1f) < 0.0001f)) { float speedCoefficient = __instance.speedCoefficient; __instance.speedCoefficient = speedCoefficient * value; if (!_loggedDistance) { _loggedDistance = true; _log.LogInfo((object)("闪现位移:速度系数 " + speedCoefficient + " -> " + __instance.speedCoefficient + "(距离 x" + value + ",持续 " + __instance.duration + "s)")); } } } internal static void TryPatchCooldown() { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (_cooldownPatched || !_enabled.Value) { return; } try { if (!((ResourceAvailability)(ref BodyCatalog.availability)).available) { return; } GameObject val = BodyCatalog.FindBodyPrefab("HuntressBody"); if ((Object)(object)val == (Object)null) { _log.LogWarning((object)"BodyCatalog 里找不到 HuntressBody,闪现冷却未修改。"); _cooldownPatched = true; return; } SkillLocator component = val.GetComponent<SkillLocator>(); if ((Object)(object)component == (Object)null || (Object)(object)component.utility == (Object)null) { _log.LogError((object)"HuntressBody 上取不到 utility 技能槽,闪现冷却未修改。"); _cooldownPatched = true; return; } SkillFamily skillFamily = component.utility.skillFamily; if ((Object)(object)skillFamily == (Object)null || skillFamily.variants == null) { _log.LogError((object)"女猎人 utility 技能族为空,闪现冷却未修改。"); _cooldownPatched = true; return; } bool flag = false; Variant[] variants = skillFamily.variants; for (int i = 0; i < variants.Length; i++) { SkillDef skillDef = variants[i].skillDef; if (!((Object)(object)skillDef == (Object)null) && IsBlinkSkillDef(skillDef)) { float value = _cooldown.Value; float baseRechargeInterval = skillDef.baseRechargeInterval; skillDef.baseRechargeInterval = value; flag = true; _log.LogInfo((object)("闪现冷却:" + baseRechargeInterval + "s -> " + value + "s(SkillDef " + skillDef.skillNameToken + ")")); } } if (!flag) { _log.LogWarning((object)"女猎人 utility 技能族里没匹配到闪现 SkillDef,冷却未修改。"); } else { RefreshLiveBodies(); } _cooldownPatched = true; } catch (Exception ex) { _cooldownPatched = true; _log.LogError((object)("修改闪现冷却异常: " + ex)); } } private static bool IsBlinkSkillDef(SkillDef def) { try { if (((SerializableEntityStateType)(ref def.activationState)).stateType == typeof(BlinkState)) { return true; } string typeName = ((SerializableEntityStateType)(ref def.activationState)).typeName; if (!string.IsNullOrEmpty(typeName) && typeName == "EntityStates.Huntress.BlinkState") { return true; } } catch (Exception) { } if (!string.IsNullOrEmpty(def.skillNameToken)) { return def.skillNameToken == "HUNTRESS_UTILITY_NAME"; } return false; } private static void RefreshLiveBodies() { foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if (HuntressSeasonedPassive.IsHuntress(readOnlyInstances)) { SkillLocator skillLocator = readOnlyInstances.skillLocator; if (!((Object)(object)skillLocator == (Object)null) && !((Object)(object)skillLocator.utility == (Object)null)) { skillLocator.utility.RecalculateValues(); } } } } } internal static class HuntressSeasonedPassive { [CompilerGenerated] private static class <>O { public static StatHookEventHandler <0>__OnGetStatCoefficients; } internal const string PassiveNameToken = "HUNTRESS_PASSIVE_NAME"; internal const string PassiveDescriptionToken = "HUNTRESS_PASSIVE_DESCRIPTION"; private const string HuntressBodyName = "HuntressBody"; private static ManualLogSource _log; private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _percentPerLevel; private static Sprite _icon; private static bool _prefabPatched; private static readonly ConditionalWeakTable<CharacterBody, StrongBox<float>> _lastLevels = new ConditionalWeakTable<CharacterBody, StrongBox<float>>(); private static bool _loggedRecalcOnce; internal static void Init(ConfigFile config, ManualLogSource log) { _log = log; _enabled = config.Bind<bool>("Passive.老练", "Enabled", true, "是否启用女猎人被动「老练」(攻击速度与暴击几率随玩家等级提升)。"); _percentPerLevel = config.Bind<float>("Passive.老练", "PercentPerLevel", 1f, "每一级玩家等级提供的攻击速度与暴击几率(%)。1 = 玩家等级 10 时 +10% 攻速和 +10% 暴击几率。"); } internal static void ApplyLanguage() { LanguageAPI.Add("HUNTRESS_PASSIVE_NAME", "Seasoned", "en"); LanguageAPI.Add("HUNTRESS_PASSIVE_DESCRIPTION", "Gain attack speed % and critical chance % equal to your level.", "en"); LanguageAPI.Add("HUNTRESS_PASSIVE_NAME", "老练", "zh-CN"); LanguageAPI.Add("HUNTRESS_PASSIVE_DESCRIPTION", "获得相当于你等级的攻击速度%与暴击几率%。", "zh-CN"); _log.LogInfo((object)"被动文本已注册: HUNTRESS_PASSIVE_NAME / HUNTRESS_PASSIVE_DESCRIPTION"); } internal static void LoadIcon() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) try { string text = Path.Combine(Path.GetDirectoryName(typeof(HuntressSeasonedPassive).Assembly.Location), "passiveIcon.png"); if (!File.Exists(text)) { _log.LogWarning((object)("找不到被动图标文件: " + text)); return; } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { _log.LogWarning((object)("被动图标解码失败: " + text)); return; } ((Texture)val).wrapMode = (TextureWrapMode)1; _icon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)_icon).name = "texSparkleHuntressSeasonedIcon"; _log.LogInfo((object)("被动图标已加载: " + text + " (" + ((Texture)val).width + "x" + ((Texture)val).height + ")")); } catch (Exception ex) { _log.LogError((object)("加载被动图标异常: " + ex)); } } internal static void TryPatchPrefab() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if (_prefabPatched) { return; } try { if (!((ResourceAvailability)(ref BodyCatalog.availability)).available) { return; } GameObject val = BodyCatalog.FindBodyPrefab("HuntressBody"); if ((Object)(object)val == (Object)null) { _log.LogWarning((object)"BodyCatalog 里找不到 HuntressBody,被动槽位未挂载。"); _prefabPatched = true; return; } SkillLocator component = val.GetComponent<SkillLocator>(); if ((Object)(object)component == (Object)null) { _log.LogError((object)"HuntressBody 上没有 SkillLocator,被动槽位未挂载。"); _prefabPatched = true; return; } PassiveSkill passiveSkill = component.passiveSkill; passiveSkill.enabled = true; passiveSkill.skillNameToken = "HUNTRESS_PASSIVE_NAME"; passiveSkill.skillDescriptionToken = "HUNTRESS_PASSIVE_DESCRIPTION"; passiveSkill.keywordToken = string.Empty; passiveSkill.icon = _icon; component.passiveSkill = passiveSkill; _prefabPatched = true; _log.LogInfo((object)("已为 HuntressBody 启用被动「老练」 icon=" + ((Object)(object)_icon != (Object)null))); } catch (Exception ex) { _prefabPatched = true; _log.LogError((object)("挂载被动槽位异常: " + ex)); } } internal static void RegisterStatHook() { //IL_0010: 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_001b: Expected O, but got Unknown object obj = <>O.<0>__OnGetStatCoefficients; if (obj == null) { StatHookEventHandler val = OnGetStatCoefficients; <>O.<0>__OnGetStatCoefficients = val; obj = (object)val; } RecalculateStatsAPI.GetStatCoefficients += (StatHookEventHandler)obj; _log.LogInfo((object)"RecalculateStatsAPI.GetStatCoefficients 钩子已注册。"); } private static void OnGetStatCoefficients(CharacterBody body, StatHookEventArgs args) { if (_enabled.Value && !((Object)(object)body == (Object)null) && IsHuntress(body)) { float level = body.level; if (!(level <= 0f)) { float num = level * _percentPerLevel.Value; args.attackSpeedMultAdd += num * 0.01f; args.critAdd += num; } } } internal static void RefreshOnPlayerLevelChange() { if (CharacterBody.readOnlyInstancesList.Count == 0) { return; } int num = 0; float num2 = 0f; foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if (IsHuntress(readOnlyInstances)) { StrongBox<float> orCreateValue = _lastLevels.GetOrCreateValue(readOnlyInstances); float level = readOnlyInstances.level; num2 = level; if (!(Math.Abs(level - orCreateValue.Value) < 0.001f)) { orCreateValue.Value = level; readOnlyInstances.RecalculateStats(); num++; } } } if (!_loggedRecalcOnce && num > 0) { _loggedRecalcOnce = true; _log.LogInfo((object)("玩家等级 " + num2 + " -> 女猎人攻速/暴击加成已生效 (重算了 " + num + " 个女猎人)。")); } } internal static bool IsHuntress(CharacterBody body) { if ((Object)(object)body == (Object)null) { return false; } string name = ((Object)body).name; if (!string.IsNullOrEmpty(name)) { return name.StartsWith("HuntressBody", StringComparison.Ordinal); } return false; } } internal static class HuntressSkillText { internal const string PrimaryNameToken = "HUNTRESS_PRIMARY_NAME"; internal const string PrimaryDescriptionToken = "HUNTRESS_PRIMARY_DESCRIPTION"; internal const string PrimaryAltNameToken = "HUNTRESS_PRIMARY_ALT_NAME"; internal const string PrimaryAltDescriptionToken = "HUNTRESS_PRIMARY_ALT_DESCRIPTION"; internal const string SpecialNameToken = "HUNTRESS_SPECIAL_NAME"; internal const string SpecialDescriptionToken = "HUNTRESS_SPECIAL_DESCRIPTION"; internal static void Apply(ManualLogSource log) { LanguageAPI.Add("HUNTRESS_PRIMARY_NAME", "扫射", "zh-CN"); LanguageAPI.Add("HUNTRESS_PRIMARY_DESCRIPTION", "<style=cIsUtility>灵巧</style>。射出<style=cIsDamage>1</style>发能够造成<style=cIsDamage>150%伤害</style>的跟踪箭。<style=cIsUtility>从攻击速度获得更多收益。</style>", "zh-CN"); LanguageAPI.Add("HUNTRESS_PRIMARY_NAME", "Strafe", "en"); LanguageAPI.Add("HUNTRESS_PRIMARY_DESCRIPTION", "<style=cIsUtility>Agile</style>. Fire <style=cIsDamage>1</style> seeking arrow for <style=cIsDamage>150% damage</style>. <style=cIsUtility>Benefits more from attack speed.</style>", "en"); LanguageAPI.Add("HUNTRESS_PRIMARY_ALT_NAME", "疾风", "zh-CN"); LanguageAPI.Add("HUNTRESS_PRIMARY_ALT_DESCRIPTION", "<style=cIsUtility>灵巧</style>。连续射出<style=cIsDamage>3</style>发能够造成<style=cIsDamage>100%伤害</style>的跟踪箭。倘若暴击则改为射出<style=cIsDamage>6</style>发。", "zh-CN"); LanguageAPI.Add("HUNTRESS_PRIMARY_ALT_NAME", "Flurry", "en"); LanguageAPI.Add("HUNTRESS_PRIMARY_ALT_DESCRIPTION", "<style=cIsUtility>Agile</style>. Fire <style=cIsDamage>3</style> seeking arrows for <style=cIsDamage>100% damage</style> each. Fires <style=cIsDamage>6</style> on a critical strike.", "en"); LanguageAPI.Add("HUNTRESS_SPECIAL_NAME", "箭雨", "zh-CN"); LanguageAPI.Add("HUNTRESS_SPECIAL_DESCRIPTION", "<style=cIsUtility>传送</style>至空中,向目标区域射下箭雨,使区域内所有敌人<style=cIsUtility>减速</style>,并持续造成<style=cIsDamage>150%的伤害</style>。", "zh-CN"); LanguageAPI.Add("HUNTRESS_SPECIAL_NAME", "Arrow Rain", "en"); LanguageAPI.Add("HUNTRESS_SPECIAL_DESCRIPTION", "<style=cIsUtility>Teleport</style> into the air, raining arrows down on a target area, <style=cIsUtility>slowing</style> all enemies and dealing <style=cIsDamage>150% damage</style> continuously.", "en"); log.LogInfo((object)"技能文案已覆盖:扫射 / 疾风 / 箭雨。"); } } internal static class HuntressStrafeAttackSpeed { private static ManualLogSource _log; private static ConfigEntry<bool> _enabled; private static ConfigEntry<float> _multiplier; private static bool _loggedOnce; internal static void Init(ConfigFile config, ManualLogSource log) { _log = log; _enabled = config.Bind<bool>("Strafe.扫射", "Enabled", true, "是否让「扫射」(M1) 的攻击速度获得额外收益。"); _multiplier = config.Bind<float>("Strafe.扫射", "AttackSpeedMultiplier", 1.5f, "攻速收益倍率。1.5 = 获得 10% 攻击速度时,射击频率相当于原版获得 15% 攻击速度;1 = 原版。"); } internal static void Patch(Harmony harmony) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(FireSeekingArrow), "OnEnter", (Type[])null, (Type[])null); if (methodInfo == null) { _log.LogError((object)"找不到 FireSeekingArrow.OnEnter,扫射攻速补丁未挂载。"); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(HuntressStrafeAttackSpeed), "OnEnterTranspiler", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)"补丁已挂载:FireSeekingArrow.OnEnter <- HuntressStrafeAttackSpeed.OnEnterTranspiler()"); } catch (Exception ex) { _log.LogError((object)("扫射攻速补丁挂载失败: " + ex)); } } private static IEnumerable<CodeInstruction> OnEnterTranspiler(IEnumerable<CodeInstruction> instructions) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(HuntressStrafeAttackSpeed), "ScaleAttackSpeed", (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (!(val.opcode != OpCodes.Ldfld)) { FieldInfo fieldInfo = val.operand as FieldInfo; if (!(fieldInfo == null) && !(fieldInfo.Name != "attackSpeedStat") && i + 1 < list.Count && !(list[i + 1].opcode != OpCodes.Div)) { list.Insert(i + 1, new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Insert(i + 2, new CodeInstruction(OpCodes.Call, (object)methodInfo)); num++; i += 2; } } } _log.LogInfo((object)("扫射攻速 IL 改写:命中 " + num + " 处 attackSpeedStat 除法(预期 2 处:状态时长 / 填充间隔)。")); return list; } private static float ScaleAttackSpeed(float attackSpeed, object state) { if (!_enabled.Value || state == null) { return attackSpeed; } if (state.GetType() != typeof(FireSeekingArrow)) { return attackSpeed; } float value = _multiplier.Value; if (value <= 0f) { return attackSpeed; } float num = 1f + value * (attackSpeed - 1f); if (num <= 0.05f) { return attackSpeed; } if (!_loggedOnce) { _loggedOnce = true; _log.LogInfo((object)("「扫射」攻速收益已生效:攻击速度 " + attackSpeed.ToString("0.00") + " → 按 " + num.ToString("0.00") + " 计算(收益 x" + value.ToString("0.##") + ")。")); } return num; } } [BepInPlugin("com.sparkletwilight.sparklehuntresstweaks", "SparkleHuntressTweaks", "1.6.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SparkleHuntressTweaksPlugin : BaseUnityPlugin { public const string PluginGUID = "com.sparkletwilight.sparklehuntresstweaks"; public const string PluginName = "SparkleHuntressTweaks"; public const string PluginVersion = "1.6.0"; internal ManualLogSource Logger; public void Awake() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0085: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; HuntressSkillText.Apply(Logger); HuntressSeasonedPassive.Init(((BaseUnityPlugin)this).Config, Logger); HuntressSeasonedPassive.ApplyLanguage(); HuntressSeasonedPassive.LoadIcon(); HuntressSeasonedPassive.RegisterStatHook(); HuntressStrafeAttackSpeed.Init(((BaseUnityPlugin)this).Config, Logger); HuntressArrowRainTweaks.Init(((BaseUnityPlugin)this).Config, Logger); HuntressBlinkTweaks.Init(((BaseUnityPlugin)this).Config, Logger); Harmony val = new Harmony("com.sparkletwilight.sparklehuntresstweaks"); HuntressStrafeAttackSpeed.Patch(val); HuntressArrowRainTweaks.Patch(val); HuntressBlinkTweaks.Patch(val); Logger.LogInfo((object)"SparkleHuntressTweaks v1.6.0 已加载。被动「老练」+ M1「扫射」攻速收益翻倍 + R「箭雨」强化 + Shift「闪现」调整。"); } public void Update() { HuntressSeasonedPassive.TryPatchPrefab(); HuntressBlinkTweaks.TryPatchCooldown(); HuntressSeasonedPassive.RefreshOnPlayerLevelChange(); } } }