Decompiled source of Rule0 ensurance v1.1.1

plugins/com.github.ChristopherJordanLamb.Rule0_ensurance.dll

Decompiled 3 weeks ago
using 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 Microsoft.CodeAnalysis;
using PEAKLib.Core;
using Photon.Pun;
using UnityEngine;
using Zorro.Core;

[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.ChristopherJordanLamb.Rule0_ensurance")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+97bb5545f9223fa04b26a0852c3c1e7d36d8ca9c")]
[assembly: AssemblyProduct("com.github.ChristopherJordanLamb.Rule0_ensurance")]
[assembly: AssemblyTitle("LoveAtFirstBite")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.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;
		}
	}
}
[BepInPlugin("com.github.ChristopherJordanLamb.Rule0_ensurance", "Rule0_ensurance", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Rule0_ensurance : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <SetTargetAfterDelay>d__27 : IEnumerator<object>, IEnumerator, IDisposable
	{
		private int <>1__state;

		private object <>2__current;

		public float delay;

		public Scoutmaster sm;

		public Character target;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <SetTargetAfterDelay>d__27(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(delay);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				sm.SetCurrentTarget(target, 120f);
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private Dictionary<Character, int> playerToTeam = new Dictionary<Character, int>();

	private Dictionary<int, HashSet<Character>> teamMembers = new Dictionary<int, HashSet<Character>>();

	private int nextTeamID;

	private HashSet<string> completedFeeds = new HashSet<string>();

	private Dictionary<string, float> activeFeedStartTimes = new Dictionary<string, float>();

	private Dictionary<string, int> feedToItemID = new Dictionary<string, int>();

	private float isolationDistance = 60f;

	private float checkInterval = 5f;

	private float timeSinceLastCheck;

	private float healingRange = 3f;

	private float healingRate = 0.1f;

	private float healingCheckInterval = 1f;

	private float timeSinceLastHealCheck;

	private void Awake()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin Rule0_ensurance is loaded!");
		GlobalEvents.OnItemConsumed = (Action<Item, Character>)Delegate.Combine(GlobalEvents.OnItemConsumed, new Action<Item, Character>(OnItemConsumed));
		LoadChocolateBundle();
	}

	private void OnDestroy()
	{
		GlobalEvents.OnItemConsumed = (Action<Item, Character>)Delegate.Remove(GlobalEvents.OnItemConsumed, new Action<Item, Character>(OnItemConsumed));
	}

	private void OnItemConsumed(Item item, Character consumer)
	{
		Character val = default(Character);
		if (!item.TryGetFeeder(ref val) && IsChocolateItem(item.itemID))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Player " + ((Object)consumer).name + " ate chocolate themselves! Spawning scoutmaster!"));
			SpawnScoutmasterForPlayer(consumer);
		}
	}

	private void LoadChocolateBundle()
	{
		try
		{
			BundleLoader.LoadBundleWithName((BaseUnityPlugin)(object)this, "valentineschocolate.autoload_peakbundle", (Action<PeakBundle>)delegate(PeakBundle peakBundle)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Valentine's chocolate bundle loaded successfully!");
				peakBundle.Mod.RegisterContent();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Valentine's chocolate item content registered!");
			});
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Error loading valentine's chocolate bundle: " + ex.Message));
			((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex.StackTrace));
		}
	}

	private void Update()
	{
		MonitorFeeds();
		timeSinceLastCheck += Time.deltaTime;
		if (timeSinceLastCheck >= checkInterval)
		{
			timeSinceLastCheck = 0f;
			if (PhotonNetwork.InRoom)
			{
				CheckAllPlayersIsolation();
			}
		}
		timeSinceLastHealCheck += Time.deltaTime;
		if (timeSinceLastHealCheck >= healingCheckInterval)
		{
			timeSinceLastHealCheck = 0f;
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				HealNearbyTeammates();
			}
		}
		if (Input.GetKeyDown((KeyCode)286))
		{
			CheckAllPlayersIsolation();
		}
		if (Input.GetKeyDown((KeyCode)287))
		{
			LogTeamInfo();
		}
		if (Input.GetKeyDown((KeyCode)288))
		{
			SpawnTestItem();
		}
	}

	private void SpawnTestItem()
	{
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: 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_0095: 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)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		Item val = ((IEnumerable<Item>)((DatabaseAsset<ItemDatabase, Item>)(object)SingletonAsset<ItemDatabase>.Instance).Objects).FirstOrDefault((Func<Item, bool>)((Item item) => (Object)(object)item != (Object)null && ((Object)item).name != null && ((Object)item).name.Contains("Chocolate")));
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Chocolate item not found in ItemDatabase! Make sure the bundle was loaded and registered.");
			return;
		}
		Character localCharacter = Character.localCharacter;
		if ((Object)(object)localCharacter == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Local character not found!");
			return;
		}
		Vector3 val2 = localCharacter.Center + ((Component)localCharacter).transform.forward * 2f;
		Item component = PhotonNetwork.InstantiateItemRoom(((Object)((Component)val).gameObject).name, val2, Quaternion.identity).GetComponent<Item>();
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Spawned chocolate item '{((Object)((Component)val).gameObject).name}' (ID: {val.itemID}) at {val2}");
	}

	private void MonitorFeeds()
	{
		if ((Object)(object)GameUtils.instance == (Object)null)
		{
			return;
		}
		FieldInfo field = typeof(GameUtils).GetField("feedData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null || !(field.GetValue(GameUtils.instance) is List<FeedData> list))
		{
			return;
		}
		HashSet<string> hashSet = new HashSet<string>();
		foreach (FeedData item in list)
		{
			string text = $"{item.giverID}_{item.receiverID}";
			hashSet.Add(text);
			if (!activeFeedStartTimes.ContainsKey(text))
			{
				activeFeedStartTimes[text] = Time.time;
				feedToItemID[text] = item.itemID;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Feed started: " + text));
			}
		}
		List<string> list2 = new List<string>();
		Character val = default(Character);
		Character val2 = default(Character);
		foreach (KeyValuePair<string, float> activeFeedStartTime in activeFeedStartTimes)
		{
			string key = activeFeedStartTime.Key;
			if (hashSet.Contains(key) || completedFeeds.Contains(key))
			{
				continue;
			}
			completedFeeds.Add(key);
			list2.Add(key);
			string[] array = key.Split('_');
			int num = int.Parse(array[0]);
			int num2 = int.Parse(array[1]);
			if (Character.GetCharacterWithPhotonID(num, ref val) && Character.GetCharacterWithPhotonID(num2, ref val2))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Feed completed: " + ((Object)val).name + " fed " + ((Object)val2).name));
				if (num == num2 && feedToItemID.ContainsKey(key) && IsChocolateItem(feedToItemID[key]))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Player " + ((Object)val).name + " fed themselves chocolate! Spawning scoutmaster!"));
					SpawnScoutmasterForPlayer(val);
				}
				else
				{
					MergeTeams(val, val2);
				}
			}
		}
		foreach (string item2 in list2)
		{
			activeFeedStartTimes.Remove(item2);
		}
		if (completedFeeds.Count > 100)
		{
			completedFeeds.Clear();
		}
	}

	private bool IsChocolateItem(int itemID)
	{
		Item val = ((IEnumerable<Item>)((DatabaseAsset<ItemDatabase, Item>)(object)SingletonAsset<ItemDatabase>.Instance).Objects).FirstOrDefault((Func<Item, bool>)((Item item) => (Object)(object)item != (Object)null && item.itemID == itemID));
		if ((Object)(object)val != (Object)null && ((Object)val).name != null)
		{
			return ((Object)val).name.Contains("Chocolate");
		}
		return false;
	}

	private void HealNearbyTeammates()
	{
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		CleanupTeams();
		foreach (KeyValuePair<int, HashSet<Character>> teamMember in teamMembers)
		{
			int key = teamMember.Key;
			HashSet<Character> value = teamMember.Value;
			if (value.Count <= 1)
			{
				continue;
			}
			List<Character> list = value.Where((Character c) => (Object)(object)c != (Object)null && !c.data.dead).ToList();
			foreach (Character item in list)
			{
				float currentStatus = item.refs.afflictions.GetCurrentStatus((STATUSTYPE)0);
				if (currentStatus <= 0f)
				{
					continue;
				}
				foreach (Character item2 in list)
				{
					if (!((Object)(object)item2 == (Object)(object)item))
					{
						float num = Vector3.Distance(item.Center, item2.Center);
						if (num <= healingRange)
						{
							float num2 = healingRate * healingCheckInterval;
							item.refs.afflictions.SubtractStatus((STATUSTYPE)0, num2, false, false);
							break;
						}
					}
				}
			}
		}
	}

	private void MergeTeams(Character player1, Character player2)
	{
		int orCreateTeam = GetOrCreateTeam(player1);
		int orCreateTeam2 = GetOrCreateTeam(player2);
		if (orCreateTeam == orCreateTeam2)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Already teammates!");
			return;
		}
		HashSet<Character> hashSet = new HashSet<Character>(teamMembers[orCreateTeam2]);
		foreach (Character item in hashSet)
		{
			playerToTeam[item] = orCreateTeam;
			teamMembers[orCreateTeam].Add(item);
		}
		teamMembers.Remove(orCreateTeam2);
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Teams merged! Team {orCreateTeam} now has {teamMembers[orCreateTeam].Count} members");
		LogTeamMembers(orCreateTeam);
	}

	private int GetOrCreateTeam(Character player)
	{
		if (playerToTeam.ContainsKey(player))
		{
			return playerToTeam[player];
		}
		int num = nextTeamID++;
		playerToTeam[player] = num;
		teamMembers[num] = new HashSet<Character> { player };
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Created team {num} for {((Object)player).name}");
		return num;
	}

	private void CheckAllPlayersIsolation()
	{
		if (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		CleanupTeams();
		foreach (KeyValuePair<Character, int> item in playerToTeam.ToList())
		{
			Character key = item.Key;
			int value = item.Value;
			if (!((Object)(object)key == (Object)null) && !key.data.dead && IsIsolatedFromTeam(key, value))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"WARNING: {((Object)key).name} is ISOLATED from team {value}!");
				SpawnScoutmasterForPlayer(key);
			}
		}
	}

	private bool IsIsolatedFromTeam(Character player, int teamID)
	{
		//IL_005c: 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 (!teamMembers.ContainsKey(teamID))
		{
			return false;
		}
		HashSet<Character> hashSet = teamMembers[teamID];
		if (hashSet.Count <= 1)
		{
			return false;
		}
		foreach (Character item in hashSet)
		{
			if (!((Object)(object)item == (Object)(object)player) && !((Object)(object)item == (Object)null) && !item.data.dead)
			{
				float num = Vector3.Distance(player.Center, item.Center);
				if (num > isolationDistance)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"  {((Object)player).name} is {num:F1}m from {((Object)item).name} (max: {isolationDistance}m)");
					return true;
				}
			}
		}
		return false;
	}

	private void SpawnScoutmasterForPlayer(Character player)
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		if (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		foreach (Scoutmaster allScoutmaster in Scoutmaster.AllScoutmasters)
		{
			if ((Object)(object)allScoutmaster.currentTarget == (Object)(object)player)
			{
				return;
			}
		}
		Vector3 spawnPositionNearPlayer = GetSpawnPositionNearPlayer(player, 30f, 50f);
		GameObject val = PhotonNetwork.InstantiateRoomObject("Character_Scoutmaster", spawnPositionNearPlayer, Quaternion.identity, (byte)0, (object[])null);
		Character component = val.GetComponent<Character>();
		component.data.spawnPoint = null;
		Scoutmaster component2 = val.GetComponent<Scoutmaster>();
		if ((Object)(object)component2 != (Object)null)
		{
			((MonoBehaviour)this).StartCoroutine(SetTargetAfterDelay(component2, player, 0.5f));
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Spawned Scoutmaster for " + ((Object)player).name));
	}

	[IteratorStateMachine(typeof(<SetTargetAfterDelay>d__27))]
	private IEnumerator SetTargetAfterDelay(Scoutmaster sm, Character target, float delay)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <SetTargetAfterDelay>d__27(0)
		{
			sm = sm,
			target = target,
			delay = delay
		};
	}

	private Vector3 GetSpawnPositionNearPlayer(Character player, float minDistance, float maxDistance)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: 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_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: 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_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: 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_0077: Unknown result type (might be due to invalid IL or missing references)
		Vector3 insideUnitSphere = Random.insideUnitSphere;
		insideUnitSphere.y = 0f;
		((Vector3)(ref insideUnitSphere)).Normalize();
		float num = Random.Range(minDistance, maxDistance);
		Vector3 val = player.Center + insideUnitSphere * num;
		RaycastHit val2 = default(RaycastHit);
		if (Physics.Raycast(val + Vector3.up * 100f, Vector3.down, ref val2, 200f))
		{
			val = ((RaycastHit)(ref val2)).point + Vector3.up * 2f;
		}
		return val;
	}

	private void CleanupTeams()
	{
		List<Character> list = new List<Character>();
		foreach (KeyValuePair<Character, int> item in playerToTeam)
		{
			if ((Object)(object)item.Key == (Object)null || item.Key.data.dead)
			{
				list.Add(item.Key);
			}
		}
		foreach (Character item2 in list)
		{
			int key = playerToTeam[item2];
			teamMembers[key].Remove(item2);
			playerToTeam.Remove(item2);
			if (teamMembers[key].Count == 0)
			{
				teamMembers.Remove(key);
			}
		}
	}

	private void LogTeamInfo()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"=== TEAMS ({teamMembers.Count} teams) ===");
		if (teamMembers.Count == 0)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"No teams formed yet. Feed items to other players to create teams!");
			return;
		}
		foreach (KeyValuePair<int, HashSet<Character>> teamMember in teamMembers)
		{
			LogTeamMembers(teamMember.Key);
		}
	}

	private void LogTeamMembers(int teamID)
	{
		if (teamMembers.ContainsKey(teamID))
		{
			string arg = string.Join(", ", teamMembers[teamID].Select((Character c) => (!((Object)(object)c != (Object)null)) ? "null" : ((Object)c).name));
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Team {teamID} ({teamMembers[teamID].Count} members): {arg}");
		}
	}
}
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 System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}