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 EasyVitals v1.0.0
plugins/EasyVitals/EasyVitals.dll
Decompiled 6 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; 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("EasyVitals")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EasyVitals")] [assembly: AssemblyTitle("EasyVitals")] [assembly: AssemblyVersion("1.0.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 EasyVitals { [BepInPlugin("easyvitals.client.only", "EasyVitals", "1.0.0")] public class EasyVitalsPlugin : BaseUnityPlugin { public const string Guid = "easyvitals.client.only"; public const string PluginName = "EasyVitals"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> WeightEnabled; internal static ConfigEntry<float> WeightMultiplier; internal static ConfigEntry<bool> FoodEnabled; internal static ConfigEntry<float> FoodDurationMultiplier; internal static ConfigEntry<bool> PotionEnabled; internal static ConfigEntry<float> PotionDurationMultiplier; internal static ConfigEntry<float> PotionMinDuration; internal static ConfigEntry<string> PotionSkipNameContains; internal static ConfigEntry<bool> MapEnabled; internal static ConfigEntry<float> MapExploreMultiplier; internal static ConfigEntry<bool> BossPowerEnabled; internal static ConfigEntry<float> BossPowerMultiplier; internal static ConfigEntry<bool> RestedEnabled; internal static ConfigEntry<float> RestedMultiplier; internal static ConfigEntry<bool> RestingEnabled; internal static ConfigEntry<float> RestingSeconds; internal static ConfigEntry<bool> MovePenaltyEnabled; internal static ConfigEntry<float> MovePenaltyValue; internal static ConfigEntry<bool> MovePenaltyOnlyExisting; internal static ConfigEntry<bool> FoodFullEnabled; private Harmony harmony; private void Awake() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Expected O, but got Unknown //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Expected O, but got Unknown //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Expected O, but got Unknown //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; WeightEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Item Weight", "Enabled", true, "物品重量修改开关。只改重量,完全不动堆叠上限。"); WeightMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Item Weight", "Multiplier", 0.25f, new ConfigDescription("物品重量倍率:0.25 = 原版 25%,1 = 原版,2 = 两倍重。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), Array.Empty<object>())); FoodEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Food Duration", "Enabled", true, "食物持续时间修改开关。"); FoodDurationMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Food Duration", "Multiplier", 5f, new ConfigDescription("食物时长倍率:5 = 原版 5 倍(物品提示里的「食物持续」会跟着变)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); PotionEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Potion Duration", "Enabled", true, "药水等消耗品的「增益效果」时长修改开关。"); PotionDurationMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Potion Duration", "Multiplier", 5f, new ConfigDescription("消耗品效果时长倍率:5 = 原版 5 倍。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>())); PotionMinDuration = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Potion Duration", "MinDuration", 300f, new ConfigDescription("只延长「原始时长 >= 该值(秒)」的效果,用来跳过药水的冷却。\n治疗/体力类蜜酒的冷却只有 120 秒,而真正的增益(抗性等)通常 300 秒以上。\n设为 0 = 不限制(连冷却也一起延长)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), Array.Empty<object>())); PotionSkipNameContains = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Potion Duration", "SkipNameContains", "", "效果名称里包含这些关键词就不延长(逗号分隔,不区分大小写)。\n留空即可,上面的 MinDuration 已经能过滤掉冷却。"); MapEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Map Discovery", "Enabled", true, "地图探索揭示半径修改开关。"); MapExploreMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Map Discovery", "Multiplier", 3f, new ConfigDescription("探索揭示半径倍率:3 = 原版 3 倍。只影响之后新探索的区域。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>())); BossPowerEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Boss Power Duration", "Enabled", true, "遗忘之力(Boss power / 被遗忘者的力量)增益时长修改开关。\n覆盖全部 GP_ 效果:Eikthyr、The Elder、Bonemass、Moder、Yagluth、Queen、Ashlands、DeepNorth。"); BossPowerMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Boss Power Duration", "Multiplier", 2f, new ConfigDescription("遗忘之力增益时长倍率:2 = 原版 2 倍(原版 5 分钟 → 10 分钟)。\n只延长「增益持续时间」,20 分钟的使用冷却完全不变(游戏里冷却和时长是两个独立数据)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 20f), Array.Empty<object>())); RestedEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Rested Duration", "Enabled", true, "「休息好了」(Rested)增益时长修改开关。"); RestedMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Rested Duration", "Multiplier", 3f, new ConfigDescription("Rested 时长倍率:3 = 原版 3 倍。\n改的是 SE_Rested 的两个「源字段」—— m_baseTTL(基准时长)与\nm_TTLPerComfortLevel(每级舒适度加成)—— 两个一起 ×倍率,所以任何舒适度都是准确的 3 倍。\n⚠\ufe0f 不能改 SE_Rested.m_ttl:游戏每次 Player.UpdateBaseValue 都会重算\n m_ttl = m_baseTTL + (舒适度等级 - 1) × m_TTLPerComfortLevel,改了会被立刻覆盖。\n只影响这个增益的持续时间,不影响「休息多久才拿到」、也不影响其它状态效果。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 20f), Array.Empty<object>())); RestingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Resting Time", "Enabled", true, "「靠火堆休息多久才获得『休息好了(Rested)』」的开关。\n改的是 SE_Cozy 的 m_delay —— 游戏发 Rested 的地方就在它身上:\n SE_Cozy.UpdateStatusEffect(): if (m_time > m_delay) 给玩家挂 Rested。\n⚠\ufe0f SE_Cozy 的 prefab 名字叫「SE_Resting」(类名 ≠ prefab 名),1.6.1 按名字找 Cozy 因此失效;\n 1.6.2 起改为按类型判定,不再依赖名字。"); RestingSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Resting Time", "Seconds", 5f, new ConfigDescription("在火堆旁累计「惬意」多少秒后获得「休息好了」。原版 20 秒,默认 5 秒。\n⚠\ufe0f 千万别去改 SE_Resting(SE_Cozy) 的 m_ttl —— 那只会让它反复到期→被重新挂上→\n 反复弹「休息中」,跟发不发 Rested 无关(1.6.0 的 bug 就是这个)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>())); MovePenaltyEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("8 - Equipment Speed", "Enabled", true, "装备/武器「移动速度惩罚」统一开关。\n原版各件装备的减速不一样(重的护甲、大盾、双手武器各有各的数值),这里统一改成同一个值。"); MovePenaltyValue = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Equipment Speed", "Value", -0.02f, new ConfigDescription("统一后的移动速度惩罚:-0.02 = -2%(原版不少装备是 -5% / -10%)。\n填 0 = 完全不减速。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0f), Array.Empty<object>())); MovePenaltyOnlyExisting = ((BaseUnityPlugin)this).Config.Bind<bool>("8 - Equipment Speed", "OnlyExistingPenalty", true, "true(默认)= 只改【本来就有减速】的装备,把它们的惩罚都统一成上面的值;\nfalse = 连本来不减速的装备也一起设成上面的值(会变成给它们加惩罚,一般不要开)。"); FoodFullEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - Food Full Effect", "Enabled", true, "食物效果保持满值:只要还吃着这份食物,最大血量和最大耐力就一直按食物的满值算,\n不再随剩余时间衰减(原版会按 Pow(剩余比例, 0.3) 逐渐减弱)。\n食物时间照旧会走完,走完后加成正常消失。"); Log.LogInfo((object)"EasyVitals 1.0.0 开始挂载 Harmony 补丁……"); FoodFullEffect.Init(); ApplyPatches(); VerifyPatches(); } private void ApplyPatches() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown harmony = new Harmony("easyvitals.client.only"); Type[] array = new Type[4] { typeof(ObjectDbAwakePatch), typeof(ZNetSceneAwakePatch), typeof(MinimapExplorePatch), typeof(PlayerGetTotalFoodValuePatch) }; int num = 0; Type[] array2 = array; foreach (Type type in array2) { try { harmony.CreateClassProcessor(type).Patch(); Log.LogInfo((object)(" 已挂载补丁类:" + type.Name)); num++; } catch (Exception ex) { Log.LogError((object)(" 挂载失败 " + type.Name + ":" + ex.Message)); } } Log.LogInfo((object)$"Harmony 补丁挂载完成:{num}/{array.Length} 成功。"); } private void VerifyPatches() { List<MethodBase> list = new List<MethodBase>(); MethodBase methodBase = AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null); if (methodBase != null) { list.Add(methodBase); } methodBase = AccessTools.Method(typeof(ZNetScene), "Awake", (Type[])null, (Type[])null); if (methodBase != null) { list.Add(methodBase); } methodBase = AccessTools.Method(typeof(Minimap), "Explore", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); if (methodBase != null) { list.Add(methodBase); } methodBase = AccessTools.Method(typeof(Player), "GetTotalFoodValue", (Type[])null, (Type[])null); if (methodBase != null) { list.Add(methodBase); } Log.LogInfo((object)"---- 补丁挂载自检 ----"); foreach (MethodBase item in list) { Patches patchInfo = Harmony.GetPatchInfo(item); int num = ((patchInfo != null && patchInfo.Prefixes != null) ? patchInfo.Prefixes.Count : 0); int num2 = ((patchInfo != null && patchInfo.Postfixes != null) ? patchInfo.Postfixes.Count : 0); string text = ((num + num2 > 0) ? "OK" : "!! 未挂上 !!"); Log.LogInfo((object)$" {item.DeclaringType.Name}.{item.Name}() prefix={num} postfix={num2} {text}"); } Log.LogInfo((object)"-----------------------"); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class FoodFullEffect { private static FieldInfo foodsField; private static FieldInfo itemField; private static FieldInfo healthField; private static FieldInfo staminaField; private static FieldInfo eitrField; private static int logCount; private static int errCount; internal static void Init() { try { foodsField = AccessTools.Field(typeof(Player), "m_foods"); Type type = null; if (foodsField != null) { Type fieldType = foodsField.FieldType; if (fieldType.IsGenericType && fieldType.GetGenericArguments().Length == 1) { type = fieldType.GetGenericArguments()[0]; } } if (type == null) { type = AccessTools.Inner(typeof(Player), "Food"); } if (type != null) { itemField = AccessTools.Field(type, "m_item"); healthField = AccessTools.Field(type, "m_health"); staminaField = AccessTools.Field(type, "m_stamina"); eitrField = AccessTools.Field(type, "m_eitr"); } EasyVitalsPlugin.Log.LogInfo((object)$"食物满值依赖检查: m_foods={foodsField != null} Food={type != null} m_item={itemField != null} m_health={healthField != null} m_stamina={staminaField != null} m_eitr={eitrField != null}"); } catch (Exception ex) { EasyVitalsPlugin.Log.LogError((object)("食物满值初始化失败:" + ex)); } } internal static void Apply(Player player, ref float hp, ref float stamina, ref float eitr) { try { if (!EasyVitalsPlugin.FoodFullEnabled.Value || (Object)(object)player == (Object)null || foodsField == null || itemField == null || healthField == null || staminaField == null || eitrField == null || !(foodsField.GetValue(player) is IEnumerable enumerable)) { return; } float num = 0f; float num2 = 0f; float num3 = 0f; int num4 = 0; foreach (object item in enumerable) { if (item == null) { continue; } object? value = itemField.GetValue(item); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val != null && val.m_shared != null) { float num5 = (float)healthField.GetValue(item); float num6 = (float)staminaField.GetValue(item); float num7 = (float)eitrField.GetValue(item); float food = val.m_shared.m_food; float foodStamina = val.m_shared.m_foodStamina; float foodEitr = val.m_shared.m_foodEitr; num += food - num5; num2 += foodStamina - num6; num3 += foodEitr - num7; if (food != num5 || foodStamina != num6 || foodEitr != num7) { healthField.SetValue(item, food); staminaField.SetValue(item, foodStamina); eitrField.SetValue(item, foodEitr); num4++; } } } if (num != 0f) { hp += num; } if (num2 != 0f) { stamina += num2; } if (num3 != 0f) { eitr += num3; } if (num4 > 0 && logCount < 5) { logCount++; EasyVitalsPlugin.Log.LogInfo((object)$"[食物满值] 补回衰减:+{num:0.#} 血 / +{num2:0.#} 耐力({num4} 项食物)"); } } catch (Exception ex) { if (errCount < 3) { errCount++; EasyVitalsPlugin.Log.LogError((object)("食物满值失败(游戏本身不受影响):" + ex)); } } } } internal static class ObjectDbApplier { private static readonly Dictionary<SharedData, float> OrigWeight = new Dictionary<SharedData, float>(); private static readonly Dictionary<SharedData, float> OrigFoodTime = new Dictionary<SharedData, float>(); private static readonly Dictionary<StatusEffect, float> OrigEffectTtl = new Dictionary<StatusEffect, float>(); private static readonly Dictionary<StatusEffect, float> OrigBossTtl = new Dictionary<StatusEffect, float>(); private static readonly Dictionary<SharedData, float> OrigMovePenalty = new Dictionary<SharedData, float>(); private static readonly Dictionary<StatusEffect, float> OrigCozyDelay = new Dictionary<StatusEffect, float>(); private static readonly Dictionary<StatusEffect, float> OrigRestedBase = new Dictionary<StatusEffect, float>(); private static readonly Dictionary<StatusEffect, float> OrigRestedPerComfort = new Dictionary<StatusEffect, float>(); private static readonly Dictionary<StatusEffect, float> OrigRestTtl = new Dictionary<StatusEffect, float>(); private static bool appliedOnce; internal static bool AppliedOnce => appliedOnce; internal static void ApplyIfReady(string source) { try { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { EasyVitalsPlugin.Log.LogWarning((object)("[" + source + "] ObjectDB 还没就绪,稍后重试。")); } else if (instance.m_items == null) { EasyVitalsPlugin.Log.LogWarning((object)("[" + source + "] ObjectDB.m_items 为 null,跳过。")); } else { Apply(instance, source); } } catch (Exception ex) { EasyVitalsPlugin.Log.LogError((object)("[" + source + "] 应用失败(游戏本身不受影响):" + ex)); } } private static void Apply(ObjectDB db, string source) { bool value = EasyVitalsPlugin.WeightEnabled.Value; bool value2 = EasyVitalsPlugin.FoodEnabled.Value; bool value3 = EasyVitalsPlugin.PotionEnabled.Value; bool value4 = EasyVitalsPlugin.BossPowerEnabled.Value; bool value5 = EasyVitalsPlugin.MovePenaltyEnabled.Value; bool value6 = EasyVitalsPlugin.RestedEnabled.Value; bool value7 = EasyVitalsPlugin.RestingEnabled.Value; float value8 = EasyVitalsPlugin.WeightMultiplier.Value; float value9 = EasyVitalsPlugin.FoodDurationMultiplier.Value; float value10 = EasyVitalsPlugin.PotionDurationMultiplier.Value; float num = Mathf.Max(0.05f, EasyVitalsPlugin.BossPowerMultiplier.Value); float value11 = EasyVitalsPlugin.MovePenaltyValue.Value; bool value12 = EasyVitalsPlugin.MovePenaltyOnlyExisting.Value; float num2 = Mathf.Max(0.05f, EasyVitalsPlugin.RestedMultiplier.Value); float num3 = Mathf.Max(0.5f, EasyVitalsPlugin.RestingSeconds.Value); float value13 = EasyVitalsPlugin.PotionMinDuration.Value; string[] array = EasyVitalsPlugin.PotionSkipNameContains.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); int num4 = 0; int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = new StringBuilder(); foreach (GameObject item in db.m_items) { if ((Object)(object)item == (Object)null) { continue; } ItemDrop component = item.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { continue; } SharedData shared = component.m_itemData.m_shared; if (shared == null) { continue; } if (value && shared.m_weight > 0f) { if (!OrigWeight.TryGetValue(shared, out var value14)) { value14 = shared.m_weight; OrigWeight[shared] = value14; } shared.m_weight = value14 * value8; num4++; } if (value2 && shared.m_foodBurnTime > 0f) { if (!OrigFoodTime.TryGetValue(shared, out var value15)) { value15 = shared.m_foodBurnTime; OrigFoodTime[shared] = value15; } shared.m_foodBurnTime = value15 * value9; num5++; } StatusEffect consumeStatusEffect = shared.m_consumeStatusEffect; if (value3 && (Object)(object)consumeStatusEffect != (Object)null && consumeStatusEffect.m_ttl > 0f) { if (!OrigEffectTtl.TryGetValue(consumeStatusEffect, out var value16)) { value16 = consumeStatusEffect.m_ttl; OrigEffectTtl[consumeStatusEffect] = value16; } bool flag = value16 < value13; if (!flag && array.Length != 0) { string text = (((Object)consumeStatusEffect).name ?? string.Empty) + "|" + (consumeStatusEffect.m_name ?? string.Empty); string[] array2 = array; for (int i = 0; i < array2.Length; i++) { string text2 = array2[i].Trim(); if (text2.Length > 0 && text.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0) { flag = true; break; } } } if (flag) { consumeStatusEffect.m_ttl = value16; num7++; if (stringBuilder.Length < 2000) { stringBuilder.AppendFormat(" 跳过 {0}(时长 {1:0}s < 阈值){2}", ((Object)consumeStatusEffect).name ?? consumeStatusEffect.m_name, value16, Environment.NewLine); } } else { consumeStatusEffect.m_ttl = value16 * value10; num6++; } } if (!value5 || shared.m_movementModifier == 0f || (value12 && !(shared.m_movementModifier < 0f))) { continue; } if (!OrigMovePenalty.TryGetValue(shared, out var value17)) { value17 = shared.m_movementModifier; OrigMovePenalty[shared] = value17; } if (Mathf.Abs(value17 - value11) > 0.0001f) { shared.m_movementModifier = value11; num8++; if (stringBuilder2.Length < 1200) { stringBuilder2.AppendFormat(" {0}: {1:P0} -> {2:P0}{3}", shared.m_name, value17, value11, Environment.NewLine); } } } int num9 = 0; int num10 = 0; int num11 = 0; StringBuilder stringBuilder3 = new StringBuilder(); StringBuilder stringBuilder4 = new StringBuilder(); if (db.m_StatusEffects != null) { foreach (StatusEffect statusEffect in db.m_StatusEffects) { if ((Object)(object)statusEffect == (Object)null) { continue; } string text3 = StatusEffectName(statusEffect); if (value4 && text3.StartsWith("GP_", StringComparison.OrdinalIgnoreCase)) { if (statusEffect.m_ttl <= 0f) { EasyVitalsPlugin.Log.LogWarning((object)$"遗忘之力 {text3} 的 m_ttl={statusEffect.m_ttl:0.##}(<=0),跳过延长。"); continue; } if (!OrigBossTtl.TryGetValue(statusEffect, out var value18)) { value18 = statusEffect.m_ttl; OrigBossTtl[statusEffect] = value18; } statusEffect.m_ttl = value18 * num; num9++; if (stringBuilder3.Length < 1500) { stringBuilder3.AppendFormat(" {0}: 增益时长 {1:0}s -> {2:0}s(冷却保持 {3:0}s 不变){4}", text3, value18, statusEffect.m_ttl, statusEffect.m_cooldown, Environment.NewLine); } continue; } SE_Rested val = (SE_Rested)(object)((statusEffect is SE_Rested) ? statusEffect : null); if (value6 && (Object)(object)val != (Object)null) { if (!OrigRestedBase.TryGetValue(statusEffect, out var value19)) { value19 = val.m_baseTTL; OrigRestedBase[statusEffect] = value19; } if (!OrigRestedPerComfort.TryGetValue(statusEffect, out var value20)) { value20 = val.m_TTLPerComfortLevel; OrigRestedPerComfort[statusEffect] = value20; } val.m_baseTTL = value19 * num2; val.m_TTLPerComfortLevel = value20 * num2; if (!OrigRestTtl.TryGetValue(statusEffect, out var value21)) { value21 = statusEffect.m_ttl; OrigRestTtl[statusEffect] = value21; } statusEffect.m_ttl = value21 * num2; num10++; if (stringBuilder4.Length < 1500) { stringBuilder4.AppendFormat(" {0}({1}): 基准 {2:0.#}s -> {3:0.#}s,每级舒适 {4:0.#}s -> {5:0.#}s,当前 {6:0.#}s -> {7:0.#}s{8}", text3, TypeName(statusEffect), value19, val.m_baseTTL, value20, val.m_TTLPerComfortLevel, value21, statusEffect.m_ttl, Environment.NewLine); } continue; } SE_Cozy val2 = (SE_Cozy)(object)((statusEffect is SE_Cozy) ? statusEffect : null); if (!value7 || !((Object)(object)val2 != (Object)null)) { continue; } if (!OrigCozyDelay.TryGetValue(statusEffect, out var value22)) { value22 = val2.m_delay; OrigCozyDelay[statusEffect] = value22; } if (Mathf.Abs(value22 - num3) > 0.001f) { val2.m_delay = num3; num11++; if (stringBuilder4.Length < 1500) { stringBuilder4.AppendFormat(" {0}({1}): 「休息好了」等待 {2:0.#}s -> {3:0.#}s{4}", text3, TypeName(statusEffect), value22, num3, Environment.NewLine); } } } } if (value4 && num9 == 0) { EasyVitalsPlugin.Log.LogWarning((object)("遗忘之力:没有匹配到任何 GP_ 效果(m_StatusEffects 数量=" + ((db.m_StatusEffects == null) ? (-1) : db.m_StatusEffects.Count) + ")。前几个名字:" + SampleNames(db))); } if (value7 && num11 == 0) { EasyVitalsPlugin.Log.LogWarning((object)("休息等待:没有在 ObjectDB 里找到 SE_Cozy 组件。" + DumpAllEffects(db))); } if (value6 && num10 == 0) { EasyVitalsPlugin.Log.LogWarning((object)("Rested 时长:没有在 ObjectDB 里找到 SE_Rested 组件。" + DumpAllEffects(db))); } appliedOnce = true; EasyVitalsPlugin.Log.LogInfo((object)$"[{source}] 已处理 {db.m_items.Count} 件物品 → 重量 x{value8}({num4} 件) | 食物时长 x{value9}({num5} 件) | 药水时长 x{value10}({num6} 个效果,跳过冷却 {num7} 个) | 移动惩罚 {value11:P0}({num8} 件)"); EasyVitalsPlugin.Log.LogInfo((object)$" → 状态效果:Boss之力 x{num}({num9} 个) | Rested 时长 x{num2}({num10} 个,改基准+每级舒适) | 「休息好了」等待 {num3:0.#}s(SE_Cozy {num11} 个)"); if (stringBuilder2.Length > 0) { EasyVitalsPlugin.Log.LogInfo((object)("---- 移动速度惩罚改动明细(前几件)----" + Environment.NewLine + stringBuilder2)); } if (stringBuilder3.Length > 0) { EasyVitalsPlugin.Log.LogInfo((object)("---- 遗忘之力(Boss power)时长明细 ----" + Environment.NewLine + stringBuilder3)); } if (stringBuilder4.Length > 0) { EasyVitalsPlugin.Log.LogInfo((object)("---- 休息相关效果明细 ----" + Environment.NewLine + stringBuilder4)); } if (stringBuilder.Length > 0) { EasyVitalsPlugin.Log.LogInfo((object)("---- 被跳过的药水效果(视为冷却)----" + Environment.NewLine + stringBuilder)); } } internal static string StatusEffectName(StatusEffect se) { string name = ((Object)se).name; if (!string.IsNullOrEmpty(name)) { return name; } return se.m_name ?? string.Empty; } private static bool NameMatches(StatusEffect se, string key) { if (!Contains(((Object)se).name, key)) { return Contains(se.m_name, key); } return true; } internal static string TypeName(StatusEffect se) { try { return ((Object)(object)se == (Object)null) ? "null" : ((object)se).GetType().Name; } catch { return "?"; } } private static string DumpAllEffects(ObjectDB db) { if (db.m_StatusEffects == null) { return "(列表为 null)"; } StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (StatusEffect statusEffect in db.m_StatusEffects) { if (!((Object)(object)statusEffect == (Object)null)) { if (num > 0) { stringBuilder.Append(" | "); } stringBuilder.Append(StatusEffectName(statusEffect)).Append('(').Append(TypeName(statusEffect)) .Append(')'); num++; } } return "共 " + num + " 个:" + stringBuilder; } private static bool Contains(string haystack, string needle) { if (!string.IsNullOrEmpty(haystack)) { return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static string SampleNames(ObjectDB db) { if (db.m_StatusEffects == null) { return "(列表为 null)"; } StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (StatusEffect statusEffect in db.m_StatusEffects) { if (!((Object)(object)statusEffect == (Object)null)) { if (num >= 12) { stringBuilder.Append(" …"); break; } num++; stringBuilder.Append(StatusEffectName(statusEffect)).Append(", "); } } if (stringBuilder.Length <= 0) { return "(空)"; } return stringBuilder.ToString(); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDbAwakePatch { [HarmonyPostfix] private static void Postfix() { ObjectDbApplier.ApplyIfReady("ObjectDB.Awake"); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { [HarmonyPostfix] private static void Postfix() { ObjectDbApplier.ApplyIfReady("ZNetScene.Awake"); } } [HarmonyPatch(typeof(Minimap), "Explore", new Type[] { typeof(Vector3), typeof(float) })] internal static class MinimapExplorePatch { [HarmonyPrefix] private static void Prefix(ref float radius) { try { if (EasyVitalsPlugin.MapEnabled.Value) { radius *= EasyVitalsPlugin.MapExploreMultiplier.Value; } } catch (Exception ex) { EasyVitalsPlugin.Log.LogError((object)("地图探索倍率失败:" + ex)); } } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] internal static class PlayerGetTotalFoodValuePatch { [HarmonyPostfix] private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { FoodFullEffect.Apply(__instance, ref hp, ref stamina, ref eitr); } } }