Decompiled source of Pet The Inkling v1.0.1

Mods/PetTheInkling.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using MelonLoader;
using Microsoft.CodeAnalysis;
using PetTheInkling;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Class1), "PetTheInkling", "1.0", "AlexHouk, TheMrEvil", null)]
[assembly: MelonGame("Alvios", "Vellum")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PetTheInkling")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+5b43ae245f43b42654b0494322f618d7f39fc7ec")]
[assembly: AssemblyProduct("PetTheInkling")]
[assembly: AssemblyTitle("PetTheInkling")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
		}
	}
}
namespace PetTheInkling
{
	[HarmonyPatch(typeof(AIDiageticInteraction), "Select")]
	public static class DiageticInteractionPatch
	{
		public static void Postfix(AIDiageticInteraction __instance)
		{
			((DiageticOption)__instance).OnInteract?.Invoke();
			__instance.InternalCooldown = __instance.Cooldown;
		}
	}
	public class Class1 : MelonMod
	{
		private bool modInitialized = false;

		private FieldInfo petOwnerIDField = null;

		private MethodInfo hasTagMethod = null;

		private PropertyInfo viewIDProperty = null;

		private float lastPetCheckTime = 0f;

		private const float PET_CHECK_INTERVAL = 3f;

		public override void OnApplicationStart()
		{
			try
			{
				petOwnerIDField = typeof(AIControl).GetField("PetOwnerID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (petOwnerIDField != null)
				{
					MelonLogger.Msg("Successfully found PetOwnerID field");
				}
				else
				{
					MelonLogger.Warning("PetOwnerID field not found");
				}
				hasTagMethod = typeof(AIControl).GetMethod("HasTag", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (hasTagMethod != null)
				{
					MelonLogger.Msg("Successfully found HasTag method");
				}
				else
				{
					MelonLogger.Warning("HasTag method not found");
				}
				viewIDProperty = typeof(PlayerControl).GetProperty("ViewID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (viewIDProperty == null)
				{
					viewIDProperty = typeof(PlayerControl).GetProperty("viewID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (viewIDProperty != null)
				{
					MelonLogger.Msg("Successfully found ViewID property");
				}
				else
				{
					MelonLogger.Warning("ViewID property not found");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error finding required members: " + ex.Message);
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			MelonLogger.Msg($"Scene loaded: {sceneName} (Build Index: {buildIndex})");
			lastPetCheckTime = 0f;
		}

		public override void OnUpdate()
		{
			if (Time.time - lastPetCheckTime >= 3f)
			{
				lastPetCheckTime = Time.time;
				CheckAndSetupPets();
			}
		}

		private void CheckAndSetupPets()
		{
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerControl myInstance = PlayerControl.myInstance;
				if ((Object)(object)myInstance == (Object)null)
				{
					return;
				}
				AIControl[] array = Object.FindObjectsOfType<AIControl>();
				int num = 0;
				int playerViewID = GetPlayerViewID(myInstance);
				AIControl[] array2 = array;
				foreach (AIControl val in array2)
				{
					try
					{
						AIDiageticInteraction componentInChildren = ((Component)val).GetComponentInChildren<AIDiageticInteraction>();
						if ((Object)(object)componentInChildren != (Object)null && componentInChildren.Label == "Pet")
						{
							continue;
						}
						bool flag = false;
						int num2 = -1;
						if (petOwnerIDField != null)
						{
							try
							{
								num2 = (int)petOwnerIDField.GetValue(val);
								flag = num2 != -1;
							}
							catch (Exception ex)
							{
								MelonLogger.Error("Error accessing PetOwnerID for " + ((Object)val).name + ": " + ex.Message);
							}
						}
						if (!flag)
						{
							bool flag2 = ((Object)val).name.ToLower().Contains("inkling") || val.AIName.ToLower().Contains("inkling");
							bool flag3 = HasTagSafe(val, "Inkling");
							bool flag4 = HasTagSafe(val, "Pet");
							flag = flag2 || flag3 || flag4;
						}
						if (flag)
						{
							MelonLogger.Msg($"Found pet/Inkling: {((Object)val).name} (Owner: {num2})");
							AIDiageticInteraction val2 = ((Component)((Component)val).transform.GetChild(0)).gameObject.AddComponent<AIDiageticInteraction>();
							val2.Label = "Pet";
							((DiageticOption)val2).InteractDistance = 2.5f;
							val2.Interactivity = (RepeatType)1;
							val2.Cooldown = 3f;
							val2.OwnerOnly = false;
							val2.Act = (InteractType)0;
							SetupPettingAction(val2, val);
							num++;
							MelonLogger.Msg($"Added pet interaction to Inkling owned by player {num2}");
						}
					}
					catch (Exception ex2)
					{
						MelonLogger.Error("Error processing AI " + ((Object)val).name + ": " + ex2.Message);
					}
				}
			}
			catch (Exception ex3)
			{
				MelonLogger.Error("Error in CheckAndSetupPets: " + ex3.Message);
			}
		}

		private bool HasTagSafe(AIControl aiControl, string tag)
		{
			try
			{
				if (hasTagMethod != null)
				{
					return (bool)hasTagMethod.Invoke(aiControl, new object[1] { tag });
				}
				return ((Object)aiControl).name.ToLower().Contains(tag.ToLower()) || aiControl.AIName.ToLower().Contains(tag.ToLower());
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error checking tag " + tag + ": " + ex.Message);
				return false;
			}
		}

		private int GetPlayerViewID(PlayerControl player)
		{
			try
			{
				if (viewIDProperty != null)
				{
					return (int)viewIDProperty.GetValue(player);
				}
				string[] array = new string[5] { "ViewID", "viewID", "ID", "ActorNr", "NetworkId" };
				string[] array2 = array;
				foreach (string name in array2)
				{
					PropertyInfo property = typeof(PlayerControl).GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (property != null && property.PropertyType == typeof(int))
					{
						return (int)property.GetValue(player);
					}
				}
				return -1;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error getting player ViewID: " + ex.Message);
				return -1;
			}
		}

		private void SetupPettingAction(AIDiageticInteraction interaction, AIControl aiControl)
		{
			AIDiageticInteraction interaction2 = interaction;
			AIControl aiControl2 = aiControl;
			try
			{
				AIDiageticInteraction obj = interaction2;
				((DiageticOption)obj).OnInteract = (Action)Delegate.Combine(((DiageticOption)obj).OnInteract, (Action)delegate
				{
					PlayerControl.myInstance.Display.Emote("emote_pet");
					ParticleSystem component = ((Component)((Component)interaction2).transform.Find("RigHead/Bubbles")).GetComponent<ParticleSystem>();
					component.Emit(320);
					((Component)((Component)component).transform.Find("Bubbles")).GetComponent<ParticleSystem>().Emit(320);
					((Component)((Component)component).transform.Find("bubble")).GetComponent<ParticleSystem>().Emit(320);
					MelonLogger.Msg(((Object)aiControl2).name + " has been pet!");
				});
				MelonLogger.Msg("Pet interaction configured for Inkling: " + ((Object)aiControl2).name);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error setting up petting action: " + ex.Message);
			}
		}

		private void CheckForNearbyPetInteractions()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerControl player = PlayerControl.myInstance;
				if ((Object)(object)player == (Object)null)
				{
					return;
				}
				AIDiageticInteraction[] source = Object.FindObjectsOfType<AIDiageticInteraction>();
				List<AIDiageticInteraction> list = source.Where((AIDiageticInteraction i) => i.Label == "Pet" && Vector3.Distance(((Component)i).transform.position, ((Component)player).transform.position) < 10f).ToList();
				if (list.Count <= 0)
				{
					return;
				}
				MelonLogger.Msg($"Found {list.Count} nearby pet interactions:");
				foreach (AIDiageticInteraction item in list)
				{
					float num = Vector3.Distance(((Component)item).transform.position, ((Component)player).transform.position);
					MelonLogger.Msg($"  - {((Object)item).name} at distance {num:F2}");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error checking nearby interactions: " + ex.Message);
			}
		}

		private bool IsOwnedByPlayer(AIControl ai, PlayerControl player)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (petOwnerIDField != null)
				{
					int num = (int)petOwnerIDField.GetValue(ai);
					int playerViewID = GetPlayerViewID(player);
					return num == playerViewID;
				}
				return Vector3.Distance(((Component)ai).transform.position, ((Component)player).transform.position) < 15f && (((Object)ai).name.ToLower().Contains("inkling") || ai.AIName.ToLower().Contains("inkling"));
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error checking pet ownership: " + ex.Message);
				return false;
			}
		}
	}
}