Decompiled source of FriendlyFireMessages v1.0.0

FriendlyFireMessages.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using CellMenu;
using GameData;
using Gear;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using StateMachines;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("FriendlyFireMessages")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FriendlyFireMessages")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b0712c2b-49df-441c-9f83-fd449f9cf0df")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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 ReTFO.GeoSpy
{
	[BepInPlugin("RoboRyGuy.FriendlyFireMessages", "FriendlyFireMessages", "1.0.0")]
	[BepInProcess("GTFO.exe")]
	public class Plugin : BasePlugin
	{
		public class UpdateComponent : MonoBehaviour
		{
			public Coroutine? UpdateCoroutine;
		}

		public class UpdateCoroutine : Object
		{
			private Plugin plugin;

			public Object Current => (Object)new WaitForSeconds(0.1f);

			public UpdateCoroutine(Plugin plugin)
				: base(ClassInjector.DerivedConstructorPointer<UpdateCoroutine>())
			{
				ClassInjector.DerivedConstructorBody((Il2CppObjectBase)(object)this);
				this.plugin = plugin;
			}

			public UpdateCoroutine(IntPtr ptr)
				: base(ptr)
			{
			}

			public bool MoveNext()
			{
				plugin.Update();
				return true;
			}

			public void Reset()
			{
			}
		}

		public class SimpleComparer : IComparer<(PlayerAgent?, PlayerAgent, bool)>
		{
			public int Compare((PlayerAgent?, PlayerAgent, bool) x, (PlayerAgent?, PlayerAgent, bool) y)
			{
				PlayerAgent? item = x.Item1;
				IntPtr intPtr = ((item != null) ? ((Il2CppObjectBase)item).Pointer : IntPtr.Zero);
				PlayerAgent? item2 = y.Item1;
				int num = intPtr.CompareTo((item2 != null) ? ((Il2CppObjectBase)item2).Pointer : IntPtr.Zero);
				if (num != 0)
				{
					return num;
				}
				num = ((Il2CppObjectBase)x.Item2).Pointer.CompareTo(((Il2CppObjectBase)y.Item2).Pointer);
				if (num != 0)
				{
					return num;
				}
				return x.Item3.CompareTo(y.Item3);
			}
		}

		public const string Name = "FriendlyFireMessages";

		public const string Author = "RoboRyGuy";

		public const string GUID = "RoboRyGuy.FriendlyFireMessages";

		public const string Version = "1.0.0";

		private static Plugin? _plugin;

		protected Harmony harmony = new Harmony("RoboRyGuy.FriendlyFireMessages");

		private const float UPDATE_DELAY = 0.1f;

		private const float TIMEOUT = 0.4f;

		private static uint s_cachedGearID;

		public SortedList<(PlayerAgent?, PlayerAgent, bool), (float, float, int)> cumulativeDamage { get; private init; } = new SortedList<(PlayerAgent, PlayerAgent, bool), (float, float, int)>(new SimpleComparer());

		public static Plugin Get()
		{
			return TryGet() ?? throw new NullReferenceException("Tried to retrieve FriendlyFireMessages, but it was not loaded!");
		}

		public static Plugin? TryGet()
		{
			return _plugin ?? (_plugin = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.FirstOrDefault((KeyValuePair<string, PluginInfo> p) => p.Key == "RoboRyGuy.FriendlyFireMessages").Value.Instance as Plugin);
		}

		public static bool TryGet([NotNullWhen(true)] out Plugin? plugin)
		{
			plugin = TryGet();
			return plugin != null;
		}

		public override void Load()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			_plugin = this;
			ClassInjector.RegisterTypeInIl2Cpp(typeof(UpdateComponent));
			Type? typeFromHandle = typeof(UpdateCoroutine);
			RegisterTypeOptions val = new RegisterTypeOptions();
			val.set_Interfaces(Il2CppInterfaceCollection.op_Implicit(new Type[1] { typeof(IEnumerator) }));
			ClassInjector.RegisterTypeInIl2Cpp(typeFromHandle, val);
			harmony.PatchAll(((object)this).GetType());
			UpdateComponent updateComponent = ((BasePlugin)this).AddComponent<UpdateComponent>();
			UpdateCoroutine updateCoroutine = new UpdateCoroutine(this);
			updateComponent.UpdateCoroutine = ((MonoBehaviour)updateComponent).StartCoroutine(new IEnumerator(((Il2CppObjectBase)updateCoroutine).Pointer));
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(11, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("RoboRyGuy.FriendlyFireMessages");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" is loaded!");
			}
			log.LogInfo(val2);
		}

		public override bool Unload()
		{
			harmony.UnpatchSelf();
			return true;
		}

		public static void ReceiveBullet(Dam_PlayerDamageBase __instance, pBulletDamageData data)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Agent val = default(Agent);
			if (!((pAgent)(ref data.source)).TryGet(ref val) || (int)val.Type != 0)
			{
				return;
			}
			Plugin plugin = Get();
			PlayerAgent val2 = ((Il2CppObjectBase)val).TryCast<PlayerAgent>();
			bool item = (Object)(object)val2 != (Object)null && data.gearCategoryId != 0 && GameDataBlockBase<GearCategoryDataBlock>.GetBlock(data.gearCategoryId).BaseItem == 97;
			(PlayerAgent, PlayerAgent, bool) key = (val2, __instance.Owner, item);
			if (!(((Il2CppObjectBase)((StateMachine<PLOC_Base>)(object)__instance.Owner.Locomotion).CurrentState).Pointer == ((Il2CppObjectBase)__instance.Owner.Locomotion.Downed).Pointer) || plugin.cumulativeDamage.ContainsKey(key))
			{
				float num = ((UFloat16)(ref data.damage)).Get(((Dam_SyncedDamageBase)__instance).DamageMax);
				int num2 = 1;
				if (plugin.cumulativeDamage.TryGetValue(key, out var value))
				{
					num += value.Item2;
					num2 += value.Item3;
				}
				plugin.cumulativeDamage[key] = (Time.fixedTime, num, num2);
			}
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageBase), "ReceiveBulletDamage")]
		[HarmonyPostfix]
		public static void ReceiveBullet_Synced(Dam_PlayerDamageBase __instance, pBulletDamageData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ReceiveBullet(__instance, data);
		}

		[HarmonyPatch(typeof(Dam_PlayerDamageLocal), "ReceiveBulletDamage")]
		[HarmonyPostfix]
		public static void ReceiveBullet_Local(Dam_PlayerDamageLocal __instance, pBulletDamageData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ReceiveBullet((Dam_PlayerDamageBase)(object)__instance, data);
		}

		public void LogForLobby(string message)
		{
			((BasePlugin)this).Log.LogInfo((object)message);
			IEnumerable<PUI_GameEventLog> source = Enumerable.Empty<PUI_GameEventLog>();
			CM_PageLoadout pageLoadout = MainMenuGuiLayer.Current.PageLoadout;
			IEnumerable<PUI_GameEventLog> source2 = source.Append((pageLoadout != null) ? pageLoadout.m_gameEventLog : null);
			CM_PageMap pageMap = MainMenuGuiLayer.Current.PageMap;
			IEnumerable<PUI_GameEventLog> source3 = source2.Append((pageMap != null) ? pageMap.m_gameEventLog : null);
			PlayerGuiLayer playerLayer = GuiManager.PlayerLayer;
			IEnumerable<PUI_GameEventLog> enumerable = source3.Append((playerLayer != null) ? playerLayer.m_gameEventLog : null);
			foreach (PUI_GameEventLog item in enumerable)
			{
				if (!((Object)(object)item == (Object)null))
				{
					item.AddLogItem(message, (eGameEventChatLogType)2);
					item.UpdateHeightOffset();
				}
			}
		}

		public void Update()
		{
			float num = Time.fixedTime - 0.4f;
			for (int i = 0; i < cumulativeDamage.Count; i++)
			{
				(float, float, int) tuple = cumulativeDamage.Values[i];
				if (!(tuple.Item1 > num))
				{
					(PlayerAgent, PlayerAgent, bool) tuple2 = cumulativeDamage.Keys[i];
					cumulativeDamage.RemoveAt(i--);
					float value = tuple.Item2 / tuple2.Item2.Damage.m_playerData.health * 100f;
					LogForLobby($"{(((Object)(object)tuple2.Item1 == (Object)null) ? "<i>Unknown</i>" : name(tuple2.Item1.Owner))}{(tuple2.Item3 ? "'s sentry" : string.Empty)} shot {name(tuple2.Item2.Owner)} for {value:0.0}% ({tuple.Item3} bullets)");
				}
			}
			static char hex(float x)
			{
				return $"{(int)((double)x * 255.0):X2}"[0];
			}
			static string name(SNet_Player player)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				return $"<#{hex(player.PlayerColor.r)}{hex(player.PlayerColor.g)}{hex(player.PlayerColor.b)}>{player.NickName}</color>";
			}
		}

		[HarmonyPatch(typeof(BulletWeapon), "Fire")]
		[HarmonyPrefix]
		public static void PreBulletFire(BulletWeapon __instance)
		{
			s_cachedGearID = ((GameDataBlockBase<GearCategoryDataBlock>)(object)((ItemEquippable)__instance).GearCategoryData).persistentID;
		}

		[HarmonyPatch(typeof(BulletWeaponSynced), "Fire")]
		[HarmonyPrefix]
		public static void PreBulletFire_Synced(BulletWeapon __instance)
		{
			s_cachedGearID = ((GameDataBlockBase<GearCategoryDataBlock>)(object)((ItemEquippable)__instance).GearCategoryData).persistentID;
		}

		[HarmonyPatch(typeof(SentryGunInstance_Firing_Bullets), "FireBullet")]
		[HarmonyPrefix]
		public static void PreBulletHit(SentryGunInstance_Firing_Bullets __instance)
		{
			SentryGunInstance obj = ((Il2CppObjectBase)__instance.m_core).TryCast<SentryGunInstance>();
			s_cachedGearID = ((obj != null) ? ((GameDataBlockBase<GearCategoryDataBlock>)(object)((ItemEquippable)obj).GearCategoryData).persistentID : 0u);
		}

		[HarmonyPatch(typeof(Dam_SyncedDamageBase), "BulletDamage")]
		[HarmonyPrefix]
		public static bool PreBulletDamage(Dam_SyncedDamageBase __instance, float dam, Agent sourceAgent, Vector3 position, Vector3 direction, Vector3 normal, bool allowDirectionalBonus, float staggerMulti, float precisionMulti, uint gearCategoryId)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			gearCategoryId = s_cachedGearID;
			pBulletDamageData val = new pBulletDamageData
			{
				allowDirectionalBonus = allowDirectionalBonus
			};
			((UFloat16)(ref val.damage)).Set(dam, __instance.DamageMax);
			((LowResVector3_Normalized)(ref val.direction)).Value = direction;
			val.gearCategoryId = gearCategoryId;
			val.limbID = 0;
			((LowResVector3)(ref val.localPosition)).Set(((Component)__instance).transform.InverseTransformPoint(position), 10f);
			((UFloat16)(ref val.precisionMulti)).Set(precisionMulti, 10f);
			((pAgent)(ref val.source)).Set(sourceAgent);
			((UFloat16)(ref val.staggerMulti)).Set(staggerMulti, 10f);
			if (__instance.SendLocally())
			{
				__instance.ReceiveBulletDamage(val);
			}
			else if (__instance.SendPacket())
			{
				if (__instance.m_onlyToMaster)
				{
					__instance.m_bulletDamagePacket.Send(val, (SNet_ChannelType)2, SNet.Master);
				}
				else
				{
					__instance.m_bulletDamagePacket.Send(val, (SNet_ChannelType)2);
				}
			}
			return false;
		}
	}
}