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 HealthExchange v1.0.0
Zichen-HealthExchange.dll
Decompiled 14 hours agousing System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Zichen-HealthExchange")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5431d17fbaba3009862f5717951e046f72b02bf3")] [assembly: AssemblyProduct("Zichen-HealthExchange")] [assembly: AssemblyTitle("Zichen-HealthExchange")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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; } } } [BepInPlugin("zichen.healthexchange", "A.Health Exchange", "1.0.0")] public sealed class WzcHealthExchangePlugin : BaseUnityPlugin { public const string PluginGuid = "zichen.healthexchange"; public const string PluginName = "A.Health Exchange"; public const string PluginVersion = "1.0.0"; private const string InfoSection = "模组信息"; private const string ExchangeSection = "A.血量交换"; private const string ModeDrain = "吸取队友血量"; private const string ModeBalance = "平均分血量"; private const string ModeOfficial = "传输队友血量"; private const string ModeDisabled = "禁用传输"; private static readonly FieldInfo PlayerHealthGrabStaticGrabObjectField = typeof(PlayerHealthGrab).GetField("staticGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerHealthGrabPhysColliderField = typeof(PlayerHealthGrab).GetField("physCollider", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerHealthGrabColliderActiveField = typeof(PlayerHealthGrab).GetField("colliderActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerHealthGrabGrabbingTimerField = typeof(PlayerHealthGrab).GetField("grabbingTimer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerHealthGrabHideLerpField = typeof(PlayerHealthGrab).GetField("hideLerp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo StaticGrabObjectPlayerGrabbingField = typeof(StaticGrabObject).GetField("playerGrabbing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerHealthHealthField = typeof(PlayerHealth).GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerHealthMaxHealthField = typeof(PlayerHealth).GetField("maxHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerAvatarIsTumblingField = typeof(PlayerAvatar).GetField("isTumbling", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo PlayerAvatarIsDisabledField = typeof(PlayerAvatar).GetField("isDisabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo RunManagerLevelIsShopField = typeof(RunManager).GetField("levelIsShop", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private Harmony harmony; private ConfigEntry<string> moduleNameInfo; private ConfigEntry<string> moduleVersionInfo; private ConfigEntry<string> contactInfo; private ConfigEntry<bool> featureEnabled; private ConfigEntry<string> exchangeMode; private ConfigEntry<string> transferRateMultiplier; public static WzcHealthExchangePlugin Instance { get; private set; } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown Instance = this; BindConfig(); harmony = new Harmony("zichen.healthexchange.patch"); harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerHealthGrab), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(WzcHealthExchangePlugin), "PlayerHealthGrabUpdatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"zichen-health-exchange loaded."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; if (Instance == this) { Instance = null; } } private void BindConfig() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Expected O, but got Unknown moduleNameInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "模组名称", "Zichen_血量交换", new ConfigDescription("当前模组的中文名称。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 1000, CustomDrawer = DrawInfo, ReadOnly = true } })); moduleNameInfo.Value = "Health Exchange / 血量交换"; moduleVersionInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "模组版本号", "1.0.0", new ConfigDescription("当前模组版本号。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 990, CustomDrawer = DrawInfo, ReadOnly = true } })); moduleVersionInfo.Value = "1.0.0"; contactInfo = ((BaseUnityPlugin)this).Config.Bind<string>("模组信息", "REPO交流QQ群", "824639225", new ConfigDescription("REPO 游戏交流、BUG 反馈、优化建议、功能请求请加 QQ 群。此处仅用于显示,不影响功能。", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 980, CustomDrawer = DrawInfo, ReadOnly = true } })); contactInfo.Value = "824639225"; featureEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("A.血量交换", "启用", true, ConfigDescriptionWithOrder("只需要主机安装即可生效。用于修改抓住队友后的血量交换逻辑。", 900)); exchangeMode = ((BaseUnityPlugin)this).Config.Bind<string>("A.血量交换", "血量交换模式", "吸取队友血量", new ConfigDescription("选择抓住队友后使用哪种血量交换方式。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "吸取队友血量", "平均分血量", "传输队友血量", "禁用传输" }), new object[1] { new ConfigurationManagerAttributes { Order = 890 } })); transferRateMultiplier = ((BaseUnityPlugin)this).Config.Bind<string>("A.血量交换", "血量传输倍率", "1", new ConfigDescription("按官方单次 10 血量为 1 倍进行放大。例如 5 倍时,单次最多传输 50 血量,实际仍以 10 为单位传输。只能选择 1 到 10 倍。", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[10] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }), new object[1] { new ConfigurationManagerAttributes { Order = 880 } })); } private void DrawInfo(ConfigEntryBase entry) { GUILayout.Label(entry.BoxedValue?.ToString() ?? string.Empty, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }); } private static ConfigDescription ConfigDescriptionWithOrder(string description, int order) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = order } }); } private bool IsFeatureEnabled() { if (featureEnabled != null) { return featureEnabled.Value; } return false; } private int GetConfiguredTransferAmount() { int result = 1; if (transferRateMultiplier != null && !string.IsNullOrEmpty(transferRateMultiplier.Value)) { int.TryParse(transferRateMultiplier.Value, out result); } return Mathf.Clamp(result, 1, 10) * 10; } private string GetMode() { if (exchangeMode != null) { return exchangeMode.Value; } return "传输队友血量"; } private static bool PlayerHealthGrabUpdatePrefix(PlayerHealthGrab __instance) { WzcHealthExchangePlugin instance = Instance; if ((Object)(object)instance == (Object)null || (Object)(object)__instance == (Object)null) { return true; } if (!instance.IsFeatureEnabled()) { return true; } instance.RunCustomHealthGrabUpdate(__instance); return false; } private void RunCustomHealthGrabUpdate(PlayerHealthGrab instance) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance.playerAvatar == (Object)null) { return; } float num = GetFieldValue(PlayerHealthGrabHideLerpField, instance, 0f); bool fieldValue = GetFieldValue(PlayerAvatarIsTumblingField, instance.playerAvatar, fallback: false); bool flag = (Object)(object)RunManager.instance != (Object)null && GetFieldValue(RunManagerLevelIsShopField, RunManager.instance, fallback: false); if (fieldValue || SemiFunc.RunIsShop() || flag || SemiFunc.RunIsArena()) { if (num < 1f) { num += Time.deltaTime * 5f; num = Mathf.Clamp(num, 0f, 1f); instance.hideTransform.localScale = new Vector3(1f, instance.hideCurve.Evaluate(num), 1f); if (num >= 1f) { ((Component)instance.hideTransform).gameObject.SetActive(false); } SetFieldValue(PlayerHealthGrabHideLerpField, instance, num); } } else if (num > 0f) { if (!((Component)instance.hideTransform).gameObject.activeSelf) { ((Component)instance.hideTransform).gameObject.SetActive(true); } num -= Time.deltaTime * 2f; num = Mathf.Clamp(num, 0f, 1f); instance.hideTransform.localScale = new Vector3(1f, instance.hideCurve.Evaluate(num), 1f); SetFieldValue(PlayerHealthGrabHideLerpField, instance, num); } bool flag2 = !GetFieldValue(PlayerAvatarIsDisabledField, instance.playerAvatar, fallback: false) && num <= 0f; bool flag3 = GetFieldValue(PlayerHealthGrabColliderActiveField, instance, fallback: true); if (flag3 != flag2) { flag3 = flag2; SetFieldValue(PlayerHealthGrabColliderActiveField, instance, flag3); object? obj = PlayerHealthGrabPhysColliderField?.GetValue(instance); Collider val = (Collider)((obj is Collider) ? obj : null); if ((Object)(object)val != (Object)null) { val.enabled = flag3; } } ((Component)instance).transform.position = instance.followTransform.position; ((Component)instance).transform.rotation = instance.followTransform.rotation; if (!flag3 || (GameManager.Multiplayer() && !PhotonNetwork.IsMasterClient)) { return; } object? obj2 = PlayerHealthGrabStaticGrabObjectField?.GetValue(instance); StaticGrabObject val2 = (StaticGrabObject)((obj2 is StaticGrabObject) ? obj2 : null); if ((Object)(object)val2 == (Object)null) { return; } if (!(StaticGrabObjectPlayerGrabbingField?.GetValue(val2) is IList list) || list.Count == 0) { SetFieldValue(PlayerHealthGrabGrabbingTimerField, instance, 0f); return; } float num2 = GetFieldValue(PlayerHealthGrabGrabbingTimerField, instance, 0f) + Time.deltaTime; if (num2 >= 1f) { for (int i = 0; i < list.Count; i++) { object? obj3 = list[i]; PhysGrabber val3 = (PhysGrabber)((obj3 is PhysGrabber) ? obj3 : null); if (!((Object)(object)val3?.playerAvatar == (Object)null)) { ProcessExchange(instance.playerAvatar, val3.playerAvatar); } } num2 = 0f; } SetFieldValue(PlayerHealthGrabGrabbingTimerField, instance, num2); } private void ProcessExchange(PlayerAvatar targetAvatar, PlayerAvatar sourceAvatar) { if ((Object)(object)targetAvatar == (Object)null || (Object)(object)sourceAvatar == (Object)null || (Object)(object)targetAvatar.playerHealth == (Object)null || (Object)(object)sourceAvatar.playerHealth == (Object)null) { return; } int configuredTransferAmount = GetConfiguredTransferAmount(); string mode = GetMode(); if (string.Equals(mode, "禁用传输", StringComparison.Ordinal)) { return; } if (string.Equals(mode, "吸取队友血量", StringComparison.Ordinal)) { TransferHealth(targetAvatar, sourceAvatar, configuredTransferAmount, notifyDonor: false); } else if (string.Equals(mode, "平均分血量", StringComparison.Ordinal)) { int health = GetHealth(targetAvatar.playerHealth); int health2 = GetHealth(sourceAvatar.playerHealth); int num = NormalizeHealthForBalance(health); int num2 = NormalizeHealthForBalance(health2); if (num == num2) { return; } int balanceTransferAmount = GetBalanceTransferAmount(Mathf.Abs(num2 - num), configuredTransferAmount); if (balanceTransferAmount >= 10) { if (num2 > num) { TransferHealth(sourceAvatar, targetAvatar, balanceTransferAmount, notifyDonor: true); } else if (num > num2) { TransferHealth(targetAvatar, sourceAvatar, balanceTransferAmount, notifyDonor: false); } } } else { TransferHealth(sourceAvatar, targetAvatar, configuredTransferAmount, notifyDonor: true); } } private static void TransferHealth(PlayerAvatar donorAvatar, PlayerAvatar receiverAvatar, int desiredAmount, bool notifyDonor) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)donorAvatar == (Object)null || (Object)(object)receiverAvatar == (Object)null || (Object)(object)donorAvatar.playerHealth == (Object)null || (Object)(object)receiverAvatar.playerHealth == (Object)null) { return; } int health = GetHealth(donorAvatar.playerHealth); int health2 = GetHealth(receiverAvatar.playerHealth); int maxHealth = GetMaxHealth(receiverAvatar.playerHealth); if (health <= 1 || health2 >= maxHealth) { return; } int num = NormalizeTransferAmount(Math.Min(desiredAmount, Math.Min(maxHealth - health2, health - 1))); if (num >= 10) { receiverAvatar.playerHealth.HealOther(num, true); donorAvatar.playerHealth.HurtOther(num, Vector3.zero, false, -1, false); if (notifyDonor) { donorAvatar.HealedOther(); } } } private static int GetHealth(PlayerHealth playerHealth) { return GetFieldValue(PlayerHealthHealthField, playerHealth, 0); } private static int GetMaxHealth(PlayerHealth playerHealth) { return GetFieldValue(PlayerHealthMaxHealthField, playerHealth, 100); } private static int GetBalanceTransferAmount(int healthDifference, int maxTransferAmount) { int val = healthDifference / 2; return NormalizeTransferAmount(Math.Min(maxTransferAmount, val)); } private static int NormalizeTransferAmount(int amount) { if (amount < 10) { return 0; } return amount / 10 * 10; } private static int NormalizeHealthForBalance(int health) { if (health < 10) { return health; } return health / 10 * 10; } private static T GetFieldValue<T>(FieldInfo field, object instance, T fallback) { try { if (field != null) { object value = field.GetValue(instance); if (value is T) { return (T)value; } } } catch { } return fallback; } private static void SetFieldValue<T>(FieldInfo field, object instance, T value) { try { field?.SetValue(instance, value); } catch { } } } internal sealed class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; }