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()) { 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)(object)IL2CPPChainloader.Instance).Plugins.FirstOrDefault((KeyValuePair 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(); 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("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(); bool item = (Object)(object)val2 != (Object)null && data.gearCategoryId != 0 && GameDataBlockBase.GetBlock(data.gearCategoryId).BaseItem == 97; (PlayerAgent, PlayerAgent, bool) key = (val2, __instance.Owner, item); if (!(((Il2CppObjectBase)((StateMachine)(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 source = Enumerable.Empty(); CM_PageLoadout pageLoadout = MainMenuGuiLayer.Current.PageLoadout; IEnumerable source2 = source.Append((pageLoadout != null) ? pageLoadout.m_gameEventLog : null); CM_PageMap pageMap = MainMenuGuiLayer.Current.PageMap; IEnumerable source3 = source2.Append((pageMap != null) ? pageMap.m_gameEventLog : null); PlayerGuiLayer playerLayer = GuiManager.PlayerLayer; IEnumerable 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) ? "Unknown" : 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}"; } } [HarmonyPatch(typeof(BulletWeapon), "Fire")] [HarmonyPrefix] public static void PreBulletFire(BulletWeapon __instance) { s_cachedGearID = ((GameDataBlockBase)(object)((ItemEquippable)__instance).GearCategoryData).persistentID; } [HarmonyPatch(typeof(BulletWeaponSynced), "Fire")] [HarmonyPrefix] public static void PreBulletFire_Synced(BulletWeapon __instance) { s_cachedGearID = ((GameDataBlockBase)(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(); s_cachedGearID = ((obj != null) ? ((GameDataBlockBase)(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; } } }