The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of Soulmates v0.2.1
plugins/com.github.Wesmania.Soulmates.dll
Decompiled 21 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; 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 ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Peak.Afflictions; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.UI; using pworld.Scripts.Extensions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.github.Wesmania.Soulmates")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.2.1.0")] [assembly: AssemblyInformationalVersion("0.2.1+615e4354dd8652ea4eaddd3a8bdf484703e169aa")] [assembly: AssemblyProduct("com.github.Wesmania.Soulmates")] [assembly: AssemblyTitle("Soulmates")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.1.0")] [module: UnverifiableCode] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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; } } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Soulmates { internal static class AfflictionUtil { public static bool sharedLolli() { if (Plugin.previousSoulmates.HasValue) { return Plugin.previousSoulmates.Value.config.sharedLolli; } return false; } public static bool sharedEnergol() { if (Plugin.previousSoulmates.HasValue) { return Plugin.previousSoulmates.Value.config.sharedEnergol; } return false; } public static void onSharedAfflictionEvent(EventData photonEvent) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) object[] array = (object[])photonEvent.CustomData; SharedAffliction sharedAffliction = SharedAffliction.Deserialize((string)array[1]); int sender = photonEvent.Sender; if (Plugin.localCharIsReady()) { Character localCharacter = Character.localCharacter; if (Plugin.soulmateNumber() == sender) { Affliction val = Affliction.CreateBlankAffliction(sharedAffliction.type); val.totalTime = sharedAffliction.totalTime; AfflictionPatch.skipMessage = true; localCharacter.refs.afflictions.AddAffliction(val, false); AfflictionPatch.skipMessage = false; } } } } [HarmonyPatch(typeof(CharacterAfflictions))] public static class AfflictionPatch { public static bool skipMessage; [HarmonyPostfix] [HarmonyPatch("AddAffliction", new Type[] { typeof(Affliction), typeof(bool) })] public static void AddAfflictionPostfix(CharacterAfflictions __instance, Affliction affliction, bool fromRPC) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (__instance.character.IsLocal && __instance.character.isLiv() && !skipMessage) { SharedAffliction e = default(SharedAffliction); if ((int)affliction.GetAfflictionType() == 1 && AfflictionUtil.sharedLolli()) { e.type = (AfflictionType)1; e.totalTime = affliction.totalTime; Events.SendSharedAfflictionEvent(e); } if ((int)affliction.GetAfflictionType() == 2 && AfflictionUtil.sharedEnergol()) { e.type = (AfflictionType)2; e.totalTime = affliction.totalTime; Events.SendSharedAfflictionEvent(e); } } } } public static class Bonk { public static void OnSharedBonkEvent(EventData photonEvent) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) object[] array = (object[])photonEvent.CustomData; SharedBonk sharedBonk = SharedBonk.Deserialize((string)array[1]); int sender = photonEvent.Sender; if (Plugin.localCharIsReady()) { Character localCharacter = Character.localCharacter; if (Plugin.soulmateNumber() == sharedBonk.victim) { localCharacter.Fall(sharedBonk.ragdollTime, 0f); localCharacter.AddForceAtPosition(sharedBonk.force.toVector3(), sharedBonk.contactPoint.toVector3(), sharedBonk.range); } } } } [HarmonyPatch(typeof(Bonkable))] public static class BonkPatch { [HarmonyPrefix] [HarmonyPatch("Bonk", new Type[] { typeof(Collision) })] public static void BonkPrefix(Bonkable __instance, Collision coll) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) Character componentInParent = coll.gameObject.GetComponentInParent<Character>(); if (Object.op_Implicit((Object)(object)componentInParent) && Time.time > __instance.lastBonkedTime + __instance.bonkCooldown && Plugin.previousSoulmates.HasValue && Plugin.previousSoulmates.Value.config.sharedBonk) { SharedBonk e = default(SharedBonk); e.ragdollTime = __instance.ragdollTime; Vector3 relativeVelocity = coll.relativeVelocity; e.force = new V3(-((Vector3)(ref relativeVelocity)).normalized * __instance.bonkForce); e.contactPoint = new V3(((ContactPoint)(ref coll.contacts[0])).point); e.range = __instance.bonkRange; e.victim = ((MonoBehaviourPun)componentInParent).photonView.Owner.ActorNumber; Events.SendSharedBonkEvent(e); } } } public static class ConnectSoulmate { private static bool globalConnectedToSoulmate; public static bool ConnectedToSoulmateStatus() { if (!Plugin.localCharIsReady()) { return false; } Character soulmate = Plugin.GetSoulmate(Plugin.soulmateNumber()); if ((Object)(object)soulmate == (Object)null) { return false; } if (!Character.localCharacter.isLiv()) { return false; } if (!soulmate.isLiv()) { return false; } return true; } public static void UpdateSoulmateStatus() { if (Plugin.localCharIsReady()) { bool flag = ConnectedToSoulmateStatus(); if (!flag && globalConnectedToSoulmate) { DisconnectFromSoulmate(); } if (flag && !globalConnectedToSoulmate) { DoConnectToSoulmate(); } globalConnectedToSoulmate = flag; } } private static void DisconnectFromSoulmate() { Plugin.Log.LogInfo((object)"Disconnecting from soulmate."); if (Plugin.localCharIsReady()) { Character localCharacter = Character.localCharacter; localCharacter.refs.afflictions.UpdateWeight(); } } private static void DoConnectToSoulmate() { if (Plugin.localCharIsReady()) { Character localCharacter = Character.localCharacter; localCharacter.refs.afflictions.UpdateWeight(); } } } public static class Events { private static void SendEvent<T>(SoulmateEventType eventType, string e, ReceiverGroup who) where T : struct { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) object[] array = new object[2] { (int)eventType, e }; RaiseEventOptions val = new RaiseEventOptions { Receivers = who }; PhotonNetwork.RaiseEvent((byte)198, (object)array, val, SendOptions.SendReliable); } private static void SendToSoulmate<T>(SoulmateEventType eventType, string e) where T : struct { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!(Plugin.globalSoulmate == "")) { object[] array = new object[2] { (int)eventType, e }; RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { Plugin.soulmateNumber() }; RaiseEventOptions val2 = val; PhotonNetwork.RaiseEvent((byte)198, (object)array, val2, SendOptions.SendReliable); } } public static void SendRecalculateSoulmateEvent(RecalculateSoulmatesEvent e) { Plugin.Log.LogInfo((object)"Sending recalculate soulmate event..."); SendEvent<RecalculateSoulmatesEvent>(SoulmateEventType.RECALCULATE, e.Serialize(), (ReceiverGroup)1); } public static void SendSharedDamageEvent(SharedDamage e) { //IL_0001: 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) if (!e.type.isShared() || e.type.isAbsolute()) { Plugin.Log.LogInfo((object)"$Tried to send a non-shared or absolute status type {statusType}"); } else { SendToSoulmate<SharedDamage>(SoulmateEventType.DAMAGE, e.Serialize()); } } public static void SendUpdateWeightEvent(UpdateWeight e) { SendEvent<UpdateWeight>(SoulmateEventType.UPDATE_WEIGHT, e.Serialize(), (ReceiverGroup)0); } public static void SendSharedBonkEvent(SharedBonk e) { Plugin.Log.LogInfo((object)$"Sending bonk {e.victim} {e.ragdollTime} {e.force} {e.contactPoint} {e.range}"); SendEvent<SharedBonk>(SoulmateEventType.SHARED_BONK, e.Serialize(), (ReceiverGroup)1); } public static void SendSharedExtraStaminaEvent(SharedExtraStamina e) { SendToSoulmate<SharedExtraStamina>(SoulmateEventType.SHARED_EXTRA_STAMINA, e.Serialize()); } public static void SendSharedAfflictionEvent(SharedAffliction e) { SendToSoulmate<SharedAffliction>(SoulmateEventType.SHARED_AFFLICTION, e.Serialize()); } } internal static class StamUtil { public static bool sharedExtraStaminaUse() { if (Plugin.previousSoulmates.HasValue) { return Plugin.previousSoulmates.Value.config.sharedExtraStaminaUse; } return false; } public static bool sharedExtraStaminaGain() { if (Plugin.previousSoulmates.HasValue) { return Plugin.previousSoulmates.Value.config.sharedExtraStaminaGain; } return false; } public static bool onlySharesGain() { if (sharedExtraStaminaGain()) { return !sharedExtraStaminaUse(); } return false; } public static void OnSharedExtraStaminaEvent(EventData photonEvent) { object[] array = (object[])photonEvent.CustomData; SharedExtraStamina sharedExtraStamina = SharedExtraStamina.Deserialize((string)array[1]); int sender = photonEvent.Sender; if (Plugin.localCharIsReady()) { Character localCharacter = Character.localCharacter; if (Plugin.soulmateNumber() == sender) { StaminaPatch.skipMessage++; localCharacter.AddExtraStamina(sharedExtraStamina.diff); StaminaPatch.skipMessage--; } } } } [HarmonyPatch(typeof(Character))] public static class StaminaPatch { public static int skipMessage; public static void SendStaminaDiff(Character __instance, float _diff) { if (!__instance.IsLocal || skipMessage > 0) { return; } float num = _diff; if (num != 0f && (!(num < 0f) || StamUtil.sharedExtraStaminaUse()) && (!(num > 0f) || StamUtil.sharedExtraStaminaGain())) { if (num > 0f && StamUtil.onlySharesGain()) { num /= 2f; } SharedExtraStamina e = default(SharedExtraStamina); e.diff = num; Events.SendSharedExtraStaminaEvent(e); } } [HarmonyPrefix] [HarmonyPatch("UseStamina", new Type[] { typeof(float), typeof(bool) })] public static void UseStaminaPrefix(Character __instance, float usage, bool useBonusStamina, out float __state) { __state = __instance.data.extraStamina; } [HarmonyPostfix] [HarmonyPatch("UseStamina", new Type[] { typeof(float), typeof(bool) })] public static void UseStaminaSuffix(Character __instance, float usage, bool useBonusStamina, float __state) { if (__instance.IsLocal) { SendStaminaDiff(__instance, __instance.data.extraStamina - __state); } } [HarmonyPrefix] [HarmonyPatch("SetExtraStamina", new Type[] { typeof(float) })] public static void SetExtraStaminaPrefix(Character __instance, float amt, out float __state) { __state = __instance.data.extraStamina; } [HarmonyPostfix] [HarmonyPatch("SetExtraStamina", new Type[] { typeof(float) })] public static void SetExtraStaminaSuffix(Character __instance, float amt, float __state) { if (__instance.IsLocal) { float num = __instance.data.extraStamina - __state; if (num > 0f && StamUtil.onlySharesGain()) { skipMessage++; __instance.AddExtraStamina((0f - num) / 2f); skipMessage--; } SendStaminaDiff(__instance, num); } } [HarmonyPrefix] [HarmonyPatch("AddExtraStamina", new Type[] { typeof(float) })] public static void AddExtraStaminaPrefix(Character __instance, ref float add, out float __state) { __state = add; if (__instance.IsLocal && add > 0f && StamUtil.onlySharesGain()) { add /= 2f; } } [HarmonyPostfix] [HarmonyPatch("AddExtraStamina", new Type[] { typeof(float) })] public static void AddExtraStaminaSuffix(Character __instance, float add, float __state) { if (__instance.IsLocal) { SendStaminaDiff(__instance, __state); } } } [HarmonyPatch(typeof(CharacterAfflictions))] public class SharedDamagePatch { internal static readonly HashSet<int> isReceivingSharedDamage = new HashSet<int>(); private static HashSet<float> SoulmateValues = new HashSet<float>(); public static void StatusPostfix(CharacterAfflictions __instance, SharedDamage _e) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) try { if (__instance.character.IsLocal && !__instance.character.data.dead && !__instance.character.warping && !isReceivingSharedDamage.Contains(((MonoBehaviourPun)__instance.character).photonView.ViewID)) { SharedDamage e = _e; if (!e.type.isAbsolute() && e.type.isShared()) { Events.SendSharedDamageEvent(e); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"Error in SetStatusPostfix: {arg}"); } } [HarmonyPrefix] [HarmonyPatch("SetStatus", new Type[] { typeof(STATUSTYPE), typeof(float) })] public static void SetStatusPrefix(CharacterAfflictions __instance, STATUSTYPE statusType, out float __state) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) __state = __instance.GetCurrentStatus(statusType); } [HarmonyPostfix] [HarmonyPatch("SetStatus", new Type[] { typeof(STATUSTYPE), typeof(float) })] public static void SetStatusPostfix(CharacterAfflictions __instance, STATUSTYPE statusType, float amount, float __state) { //IL_0001: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) float currentStatus = __instance.GetCurrentStatus(statusType); float num = currentStatus - __state; if (num != 0f) { if (!statusType.isAbsolute()) { SharedDamage e = default(SharedDamage); e.type = statusType; e.value = num; e.kind = SharedDamageKind.SET; StatusPostfix(__instance, e); } } } [HarmonyPostfix] [HarmonyPatch("AddStatus", new Type[] { typeof(STATUSTYPE), typeof(float), typeof(bool) })] public static void AddStatusPostfix(CharacterAfflictions __instance, STATUSTYPE statusType, float amount, bool fromRPC) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) SharedDamage e = default(SharedDamage); e.type = statusType; e.value = amount; e.kind = SharedDamageKind.ADD; StatusPostfix(__instance, e); } [HarmonyPostfix] [HarmonyPatch("SubtractStatus", new Type[] { typeof(STATUSTYPE), typeof(float), typeof(bool) })] public static void SubtractStatusPostfix(CharacterAfflictions __instance, STATUSTYPE statusType, float amount, bool fromRPC) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) SharedDamage e = default(SharedDamage); e.type = statusType; e.value = amount; e.kind = SharedDamageKind.SUBTRACT; StatusPostfix(__instance, e); } } [HarmonyPatch(typeof(Character))] public static class RecalculateSoulmatesPatch { [HarmonyPostfix] [HarmonyPatch("StartPassedOutOnTheBeach")] public static void StartPassedOutOnTheBeachPostfix(Character __instance) { Plugin.Log.LogInfo((object)"Passed out on the beach function"); if (__instance.IsLocal) { RecalculateSoulmatesEvent? recalculateSoulmatesEvent = Plugin.RecalculateSoulmate(firstTime: true); if (recalculateSoulmatesEvent.HasValue) { Events.SendRecalculateSoulmateEvent(recalculateSoulmatesEvent.Value); } } } [HarmonyPostfix] [HarmonyPatch("Update")] public static void UpdatePostfix(Character __instance) { if (__instance.IsLocal) { ConnectSoulmate.UpdateSoulmateStatus(); Weight.MaybeSendWeight(); } } } [HarmonyPatch(typeof(Campfire))] public static class RecalculateSoulmatesPatch2 { [HarmonyPostfix] [HarmonyPatch("Light_Rpc")] public static void LightPostfix(Campfire __instance) { Plugin.Log.LogInfo((object)"Campfire function"); RecalculateSoulmatesEvent? recalculateSoulmatesEvent = Plugin.RecalculateSoulmate(firstTime: false); if (recalculateSoulmatesEvent.HasValue) { Events.SendRecalculateSoulmateEvent(recalculateSoulmatesEvent.Value); } } } public static class Extensions { public static bool isAbsolute(this STATUSTYPE t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)t != 7) { return (int)t == 9; } return true; } public static bool isShared(this STATUSTYPE t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 return (int)t != 5; } public static bool isLiv(this Character c) { if (!c.data.dead) { return !c.warping; } return false; } } [BepInPlugin("com.github.Wesmania.Soulmates", "Soulmates", "0.2.1")] public class Plugin : BaseUnityPlugin { internal const byte SHARED_DAMAGE_EVENT_CODE = 198; public static string globalSoulmate = ""; public static RecalculateSoulmatesEvent? previousSoulmates; public const string Id = "com.github.Wesmania.Soulmates"; internal static ManualLogSource Log { get; private set; } = null; internal static ConfigEntry<bool> Enabled { get; private set; } = null; internal static ConfigEntry<bool> EnableSharedBonk { get; private set; } = null; internal static ConfigEntry<bool> EnableSharedSlip { get; private set; } = null; internal static ConfigEntry<bool> EnableSharedExtraStaminaGain { get; private set; } = null; internal static ConfigEntry<bool> EnableSharedExtraStaminaUse { get; private set; } = null; internal static ConfigEntry<bool> EnableSharedLolli { get; private set; } = null; internal static ConfigEntry<bool> EnableSharedEnergol { get; private set; } = null; public static string Name => "Soulmates"; public static string Version => "0.2.1"; private void Awake() { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)("Plugin " + Name + " version 0.2.1 is loaded!")); Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Enabled", "Enabled", true, "Enable/disable the mod with this"); EnableSharedBonk = ((BaseUnityPlugin)this).Config.Bind<bool>("Shared Bonk", "EnableSharedBonk", true, "Bonking a player bonks his soulmate too"); EnableSharedSlip = ((BaseUnityPlugin)this).Config.Bind<bool>("Shared Slip", "EnableSharedSlip", true, "Slipping on something makes the soulmate slip too"); EnableSharedExtraStaminaGain = ((BaseUnityPlugin)this).Config.Bind<bool>("Shared extra stamina gain", "EnableSharedExtraStaminaGain", true, "Soulmates share extra stamina gained"); EnableSharedExtraStaminaUse = ((BaseUnityPlugin)this).Config.Bind<bool>("Shared extra stamina use", "EnableSharedExtraStaminaUse", true, "Soulmates use a single extra stamina pool"); EnableSharedLolli = ((BaseUnityPlugin)this).Config.Bind<bool>("Shared lollipops", "EnableSharedLolli", true, "Soulmates share lollipop boost"); EnableSharedEnergol = ((BaseUnityPlugin)this).Config.Bind<bool>("Shared energy drinks", "EnableSharedEnergol", true, "Soulmates share energy drink boost"); if (!Enabled.Value) { Log.LogInfo((object)"Soulmates disabled"); return; } PhotonNetwork.NetworkingClient.EventReceived += OnEvent; Harmony val = new Harmony("com.github.Wesmania.Soulmates"); try { val.PatchAll(); } catch (Exception arg) { Log.LogError((object)$"Failed to load mod: {arg}"); } } private void OnDestroy() { if (Enabled.Value && PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived -= OnEvent; } } public static bool localCharIsReady() { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null || !localCharacter.isLiv()) { return false; } return true; } public static int soulmateNumber() { if (globalSoulmate == "") { return -1; } Player val = PhotonNetwork.PlayerList.ToList().Find((Player p) => p.NickName == globalSoulmate); if (val == null) { return -1; } return val.ActorNumber; } public static string indexToNick(int idx) { Player val = PhotonNetwork.PlayerList.ToList().Find((Player p) => p.ActorNumber == idx); if (val == null) { return ""; } return val.NickName; } private void OnEvent(EventData photonEvent) { if (photonEvent.Code == 198) { object[] array = (object[])photonEvent.CustomData; switch ((int)array[0]) { case 0: OnRecalculateSoulmateEvent(photonEvent); break; case 1: OnSharedDamageEvent(photonEvent); break; case 2: Weight.OnUpdateWeightEvent(photonEvent); break; case 4: Bonk.OnSharedBonkEvent(photonEvent); break; case 5: StamUtil.OnSharedExtraStaminaEvent(photonEvent); break; case 6: AfflictionUtil.onSharedAfflictionEvent(photonEvent); break; case 3: break; } } } private void OnSharedDamageEvent(EventData photonEvent) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) object[] array = (object[])photonEvent.CustomData; SharedDamage sharedDamage = SharedDamage.Deserialize((string)array[1]); int sender = photonEvent.Sender; if (!localCharIsReady()) { return; } Character localCharacter = Character.localCharacter; if (sender != soulmateNumber()) { return; } if (!sharedDamage.type.isShared()) { Log.LogInfo((object)$"Received update for non-shared damage type {sharedDamage.type}"); return; } if (sharedDamage.type.isAbsolute()) { Log.LogInfo((object)$"Received an update request for an absolute damage type {sharedDamage.type}"); return; } SharedDamagePatch.isReceivingSharedDamage.Add(((MonoBehaviourPun)localCharacter).photonView.ViewID); CharacterAfflictions afflictions = localCharacter.refs.afflictions; try { switch (sharedDamage.kind) { case SharedDamageKind.ADD: afflictions.AddStatus(sharedDamage.type, sharedDamage.value, false); break; case SharedDamageKind.SUBTRACT: afflictions.SubtractStatus(sharedDamage.type, sharedDamage.value, false); break; case SharedDamageKind.SET: { float currentStatus = afflictions.GetCurrentStatus(sharedDamage.type); afflictions.SetStatus(sharedDamage.type, currentStatus + sharedDamage.value); break; } } } finally { SharedDamagePatch.isReceivingSharedDamage.Remove(((MonoBehaviourPun)localCharacter).photonView.ViewID); } } private static string findSoulmate(List<int> soulmates) { int my_actor = PhotonNetwork.LocalPlayer.ActorNumber; int num = soulmates.FindIndex((int x) => x == my_actor); if (num == -1) { Log.LogInfo((object)$"Did not find myself ({my_actor}) on soulmate list!"); return ""; } Log.LogInfo((object)$"Found my index: {num}"); int num2 = ((num % 2 == 0) ? (num + 1) : (num - 1)); if (num2 >= soulmates.Count) { Log.LogInfo((object)$"I am last player on the list and have no soulmate"); return ""; } return indexToNick(soulmates[num2]); } public static Character? GetSoulmate(int actor) { try { return Character.AllCharacters.Find((Character c) => ((MonoBehaviourPun)c).photonView.Owner.ActorNumber == actor); } catch (Exception) { return null; } } private static void ConnectToNewSoulmate(RecalculateSoulmatesEvent e) { if (localCharIsReady()) { Character localCharacter = Character.localCharacter; int actorNumber = ((MonoBehaviourPun)localCharacter).photonView.Owner.ActorNumber; localCharacter.refs.afflictions.UpdateWeight(); } } private static void OnRecalculateSoulmateEvent(EventData photonEvent) { Log.LogInfo((object)"Received recalculate soulmate event"); object[] array = (object[])photonEvent.CustomData; RecalculateSoulmatesEvent recalculateSoulmatesEvent = RecalculateSoulmatesEvent.Deserialize((string)array[1]); previousSoulmates = recalculateSoulmatesEvent; string text = globalSoulmate; globalSoulmate = findSoulmate(recalculateSoulmatesEvent.soulmates); if (globalSoulmate == "") { Log.LogInfo((object)"No soulmate"); } else { Log.LogInfo((object)("New soulmate: " + globalSoulmate)); } if (recalculateSoulmatesEvent.firstTime) { Weight.Clear(); } else { ConnectToNewSoulmate(recalculateSoulmatesEvent); } if (globalSoulmate == "") { SoulmateTextPatch.SetSoulmateText("Soulmate: None", 10f); return; } Log.LogInfo((object)$"My soulmate is {globalSoulmate})"); SoulmateTextPatch.SetSoulmateText("Soulmate: " + globalSoulmate, 10f); } public static RecalculateSoulmatesEvent? RecalculateSoulmate(bool firstTime) { Log.LogInfo((object)"Recalculating soulmate"); Log.LogInfo((object)$"Character count: {PhotonNetwork.PlayerList.Count()}"); List<int> list = PhotonNetwork.PlayerList.Select((Player x) => x.ActorNumber).ToList(); list.Sort(); string text = string.Join(" ", PhotonNetwork.PlayerList.Select((Player x) => ((object)x).ToString())); Log.LogInfo((object)("Characters: " + text)); if (!PhotonNetwork.IsMasterClient) { return null; } Log.LogInfo((object)"I am master client, preparing new soulmate list"); ExtCollections.Shuffle<int>((IList<int>)list); RecalculateSoulmatesEvent value = default(RecalculateSoulmatesEvent); value.soulmates = list; value.firstTime = firstTime; if (firstTime) { previousSoulmates = null; } if (previousSoulmates.HasValue) { value.config = previousSoulmates.Value.config; } else { value.config.sharedBonk = EnableSharedBonk.Value; value.config.sharedSlip = EnableSharedSlip.Value; value.config.sharedExtraStaminaGain = EnableSharedExtraStaminaGain.Value; value.config.sharedExtraStaminaUse = EnableSharedExtraStaminaUse.Value; value.config.sharedLolli = EnableSharedLolli.Value; value.config.sharedEnergol = EnableSharedEnergol.Value; } return value; } } [HarmonyPatch(typeof(SlipperyJellyfish))] public static class SlipPatch1 { [HarmonyPrefix] [HarmonyPatch("OnTriggerEnter", new Type[] { typeof(Collider) })] public static void OnTriggerEnterPrefix(SlipperyJellyfish __instance, Collider other) { if (Plugin.previousSoulmates.HasValue && Plugin.previousSoulmates.Value.config.sharedSlip && !(__instance.counter < 3f)) { Character componentInParent = ((Component)other).GetComponentInParent<Character>(); if (Object.op_Implicit((Object)(object)componentInParent) && ((MonoBehaviourPun)componentInParent).photonView.Owner.ActorNumber == Plugin.soulmateNumber()) { __instance.counter = 0f; __instance.relay.view.RPC("RPCA_TriggerWithTarget", (RpcTarget)0, new object[2] { ((Component)__instance).transform.GetSiblingIndex(), Character.localCharacter.refs.view.ViewID }); } } } } [HarmonyPatch(typeof(BananaPeel))] public static class SlipPatch2 { [HarmonyPrefix] [HarmonyPatch("Update")] public static void UpdatePrefix(BananaPeel __instance) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.previousSoulmates.HasValue || !Plugin.previousSoulmates.Value.config.sharedSlip) { return; } Character soulmate = Plugin.GetSoulmate(Plugin.soulmateNumber()); if (!((Object)(object)soulmate == (Object)null) && (int)__instance.item.itemState == 0) { __instance.counter += Time.deltaTime; if (!(__instance.counter < 3f) && !(Vector3.Distance(soulmate.Center, ((Component)__instance).transform.position) > 1f) && soulmate.data.isGrounded && !(((Vector3)(ref soulmate.data.avarageVelocity)).magnitude < 1.5f)) { __instance.counter = 0f; ((Component)__instance).GetComponent<PhotonView>().RPC("RPCA_TriggerBanana", (RpcTarget)0, new object[1] { Character.localCharacter.refs.view.ViewID }); } } } } [HarmonyPatch(typeof(GUIManager))] public static class SoulmateTextPatch { public static Canvas? SoulmatePrompt; public static TextMeshProUGUI? text; public static TMP_FontAsset? darumaDropOneFont; public static TextSetter? text_setter; [HarmonyPostfix] [HarmonyPatch("Start")] public static void StartPostfix(GUIManager __instance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown Transform transform = ((Component)__instance).transform; GameObject val = new GameObject("SoulmatePrompt"); val.transform.SetParent(transform, false); SoulmatePrompt = val.AddComponent<Canvas>(); SoulmatePrompt.renderMode = (RenderMode)1; CanvasScaler val2 = ((Component)SoulmatePrompt).gameObject.GetComponent<CanvasScaler>() ?? ((Component)SoulmatePrompt).gameObject.AddComponent<CanvasScaler>(); val2.referencePixelsPerUnit = 100f; val2.matchWidthOrHeight = 1f; val2.referenceResolution = new Vector2(1920f, 1080f); val2.scaleFactor = 1f; val2.screenMatchMode = (ScreenMatchMode)0; val2.uiScaleMode = (ScaleMode)1; GameObject val3 = new GameObject("TextChat"); val3.transform.SetParent(((Component)SoulmatePrompt).transform, false); text = val3.AddComponent<TextMeshProUGUI>(); text_setter = val3.AddComponent<TextSetter>(); try { GUIManager instance = GUIManager.instance; object obj; if (instance == null) { obj = null; } else { TextMeshProUGUI itemPromptDrop = instance.itemPromptDrop; obj = ((itemPromptDrop != null) ? ((TMP_Text)itemPromptDrop).font : null); } darumaDropOneFont = (TMP_FontAsset?)obj; } catch { } ((TMP_Text)text).text = ""; if ((Object)(object)darumaDropOneFont != (Object)null) { ((TMP_Text)text).font = darumaDropOneFont; } ((TMP_Text)text).horizontalAlignment = (HorizontalAlignmentOptions)2; } public static void SetSoulmateText(string text, float delay) { if ((Object)(object)text_setter != (Object)null) { text_setter.SetSoulmateText(text, delay); } } } public class TextSetter : MonoBehaviour { public void SetSoulmateText(string text, float delay) { string text2 = text; Plugin.Log.LogInfo((object)"In SetSoulmateText"); ((MonoBehaviour)this).StartCoroutine(TextCoroutine()); IEnumerator TextCoroutine() { Plugin.Log.LogInfo((object)"In SetSoulmateText coroutine"); yield return (object)new WaitForSeconds(delay); if ((Object)(object)SoulmateTextPatch.text != (Object)null) { Plugin.Log.LogInfo((object)"In SetSoulmateText coroutine, set text"); ((TMP_Text)SoulmateTextPatch.text).text = text2; } yield return (object)new WaitForSeconds(10f); if ((Object)(object)SoulmateTextPatch.text != (Object)null) { Plugin.Log.LogInfo((object)"In SetSoulmateText coroutine, reset text"); ((TMP_Text)SoulmateTextPatch.text).text = ""; } Plugin.Log.LogInfo((object)"In SetSoulmateText coroutine end"); } } } [Serializable] public struct Config { public bool sharedBonk; public bool sharedSlip; public bool sharedExtraStaminaGain; public bool sharedExtraStaminaUse; public bool sharedLolli; public bool sharedEnergol; } [Serializable] public struct RecalculateSoulmatesEvent { public Config config; public List<int> soulmates; public bool firstTime; public string Serialize() { return JsonConvert.SerializeObject((object)this); } public static RecalculateSoulmatesEvent Deserialize(string s) { return JsonConvert.DeserializeObject<RecalculateSoulmatesEvent>(s); } } [Serializable] public enum SharedDamageKind { ADD, SUBTRACT, SET } [Serializable] public struct SharedDamage { public STATUSTYPE type; public float value; public SharedDamageKind kind; public string Serialize() { return JsonConvert.SerializeObject((object)this); } public static SharedDamage Deserialize(string s) { return JsonConvert.DeserializeObject<SharedDamage>(s); } } [Serializable] public struct UpdateWeight { public float weight; public float thorns; public UpdateWeight() { weight = 0f; thorns = 0f; } public string Serialize() { return JsonConvert.SerializeObject((object)this); } public static UpdateWeight Deserialize(string s) { return JsonConvert.DeserializeObject<UpdateWeight>(s); } } [Serializable] public struct V3 { public float x; public float y; public float z; public V3(Vector3 v) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) x = v.x; y = v.y; z = v.z; } public Vector3 toVector3() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(x, y, z); } } [Serializable] public struct SharedBonk { public int victim; public float ragdollTime; public V3 force; public V3 contactPoint; public float range; public string Serialize() { return JsonConvert.SerializeObject((object)this); } public static SharedBonk Deserialize(string s) { return JsonConvert.DeserializeObject<SharedBonk>(s); } } public struct SharedExtraStamina { public float diff; public string Serialize() { return JsonConvert.SerializeObject((object)this); } public static SharedExtraStamina Deserialize(string s) { return JsonConvert.DeserializeObject<SharedExtraStamina>(s); } } public struct SharedAffliction { public AfflictionType type; public float totalTime; public string Serialize() { return JsonConvert.SerializeObject((object)this); } public static SharedAffliction Deserialize(string s) { return JsonConvert.DeserializeObject<SharedAffliction>(s); } } internal enum SoulmateEventType { RECALCULATE = 0, DAMAGE = 1, UPDATE_WEIGHT = 2, SHARED_BONK = 4, SHARED_EXTRA_STAMINA = 5, SHARED_AFFLICTION = 6 } public static class Weight { public static Dictionary<int, UpdateWeight> playerWeights = new Dictionary<int, UpdateWeight>(); public static bool shouldSendWeight; public static void Clear() { playerWeights.Clear(); shouldSendWeight = false; } public static bool updateLocalWeight(UpdateWeight w) { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { return false; } int actorNumber = ((MonoBehaviourPun)localCharacter).photonView.Owner.ActorNumber; if (!playerWeights.ContainsKey(actorNumber)) { playerWeights[actorNumber] = w; return true; } UpdateWeight updateWeight = playerWeights[actorNumber]; playerWeights[actorNumber] = w; if (updateWeight.weight == w.weight) { return updateWeight.thorns != w.thorns; } return true; } public static UpdateWeight? getLocalWeight() { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter == (Object)null) { return null; } int actorNumber = ((MonoBehaviourPun)localCharacter).photonView.Owner.ActorNumber; if (!playerWeights.ContainsKey(actorNumber)) { return null; } return playerWeights[actorNumber]; } public static void OnUpdateWeightEvent(EventData photonEvent) { object[] array = (object[])photonEvent.CustomData; UpdateWeight value = UpdateWeight.Deserialize((string)array[1]); int sender = photonEvent.Sender; playerWeights[sender] = value; if (sender == Plugin.soulmateNumber() && Plugin.localCharIsReady()) { Character.localCharacter.refs.afflictions.UpdateWeight(); } } public static void RecalculateSharedWeight() { if (!Plugin.localCharIsReady()) { return; } Character localCharacter = Character.localCharacter; CharacterAfflictions afflictions = localCharacter.refs.afflictions; float currentStatus = afflictions.GetCurrentStatus((STATUSTYPE)9); float currentStatus2 = afflictions.GetCurrentStatus((STATUSTYPE)7); Character soulmate = Plugin.GetSoulmate(Plugin.soulmateNumber()); if (!((Object)(object)soulmate == (Object)null) && soulmate.isLiv()) { if (!playerWeights.ContainsKey(Plugin.soulmateNumber())) { Plugin.Log.LogInfo((object)("No player weight entry for soulmate " + Plugin.globalSoulmate)); return; } UpdateWeight updateWeight = playerWeights[Plugin.soulmateNumber()]; float num = (currentStatus2 + updateWeight.weight) / 2f; float num2 = currentStatus + updateWeight.thorns; afflictions.SetStatus((STATUSTYPE)7, num); afflictions.SetStatus((STATUSTYPE)9, num2); } } public static bool ShouldSendWeight() { bool result = shouldSendWeight; shouldSendWeight = false; return result; } public static void MaybeSendWeight() { if (ShouldSendWeight()) { UpdateWeight? localWeight = getLocalWeight(); if (localWeight.HasValue) { Events.SendUpdateWeightEvent(localWeight.Value); } } } } [HarmonyPatch(typeof(CharacterAfflictions))] public class WeightPatch1 { [HarmonyPostfix] [HarmonyPatch("UpdateWeight")] public static void UpdateWeightPostfix(CharacterAfflictions __instance) { if (!((Object)(object)Character.localCharacter == (Object)null)) { CharacterAfflictions afflictions = Character.localCharacter.refs.afflictions; UpdateWeight w = default(UpdateWeight); w.weight = afflictions.GetCurrentStatus((STATUSTYPE)7); w.thorns = afflictions.GetCurrentStatus((STATUSTYPE)9); if (Weight.updateLocalWeight(w)) { Weight.shouldSendWeight = true; } Weight.RecalculateSharedWeight(); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }